@mastra/observability 1.12.0-alpha.0 → 1.12.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 +28 -0
- package/dist/bus/observability-bus.d.ts +21 -4
- package/dist/bus/observability-bus.d.ts.map +1 -1
- package/dist/bus/route-event.d.ts +8 -1
- package/dist/bus/route-event.d.ts.map +1 -1
- package/dist/default.d.ts.map +1 -1
- package/dist/exporters/default.d.ts +2 -0
- package/dist/exporters/default.d.ts.map +1 -1
- package/dist/exporters/event-buffer.d.ts +4 -4
- package/dist/exporters/event-buffer.d.ts.map +1 -1
- package/dist/features.d.ts +39 -0
- package/dist/features.d.ts.map +1 -0
- package/dist/index.cjs +301 -44
- 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 +301 -45
- package/dist/index.js.map +1 -1
- package/dist/metrics/pricing-data.jsonl +706 -411
- package/dist/model-tracing.d.ts +34 -4
- package/dist/model-tracing.d.ts.map +1 -1
- package/dist/recorded.d.ts.map +1 -1
- package/dist/spans/base.d.ts.map +1 -1
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -14,5 +14,6 @@ export * from './spans/index.js';
|
|
|
14
14
|
export * from './exporters/index.js';
|
|
15
15
|
export * from './span_processors/index.js';
|
|
16
16
|
export * from './model-tracing.js';
|
|
17
|
+
export * from './features.js';
|
|
17
18
|
export * from './tracing-options.js';
|
|
18
19
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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,OAAO,CAAC;AACtB,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AAExB,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,OAAO,CAAC;AACtB,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AAExB,cAAc,aAAa,CAAC;AAC5B,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAIhC,cAAc,YAAY,CAAC;AAG3B,cAAc,mBAAmB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -8,6 +8,7 @@ import fs from 'fs';
|
|
|
8
8
|
import { createRequire } from 'module';
|
|
9
9
|
import path from 'path';
|
|
10
10
|
import { TransformStream } from 'stream/web';
|
|
11
|
+
import { coreFeatures } from '@mastra/core/features';
|
|
11
12
|
|
|
12
13
|
var __defProp = Object.defineProperty;
|
|
13
14
|
var __export = (target, all) => {
|
|
@@ -37,6 +38,23 @@ function routeToHandler(handler, event, logger) {
|
|
|
37
38
|
if (handler.onScoreEvent) {
|
|
38
39
|
return catchAsyncResult(handler.onScoreEvent(event), handler.name, "score", logger);
|
|
39
40
|
}
|
|
41
|
+
if (handler.addScoreToTrace) {
|
|
42
|
+
const score = event.score;
|
|
43
|
+
if (!score.traceId) break;
|
|
44
|
+
return catchAsyncResult(
|
|
45
|
+
handler.addScoreToTrace({
|
|
46
|
+
traceId: score.traceId,
|
|
47
|
+
...score.spanId ? { spanId: score.spanId } : {},
|
|
48
|
+
score: score.score,
|
|
49
|
+
...score.reason ? { reason: score.reason } : {},
|
|
50
|
+
scorerName: score.scorerName ?? score.scorerId,
|
|
51
|
+
...score.metadata ? { metadata: score.metadata } : {}
|
|
52
|
+
}),
|
|
53
|
+
handler.name,
|
|
54
|
+
"score",
|
|
55
|
+
logger
|
|
56
|
+
);
|
|
57
|
+
}
|
|
40
58
|
break;
|
|
41
59
|
case "feedback":
|
|
42
60
|
if (handler.onFeedbackEvent) {
|
|
@@ -48,6 +66,15 @@ function routeToHandler(handler, event, logger) {
|
|
|
48
66
|
logger.error(`[Observability] Handler error [handler=${handler.name}]:`, err);
|
|
49
67
|
}
|
|
50
68
|
}
|
|
69
|
+
function routeDropToHandler(handler, event, logger) {
|
|
70
|
+
try {
|
|
71
|
+
if (handler.onDroppedEvent) {
|
|
72
|
+
return catchAsyncResult(handler.onDroppedEvent(event), handler.name, "drop", logger);
|
|
73
|
+
}
|
|
74
|
+
} catch (err) {
|
|
75
|
+
logger.error(`[Observability] Handler error [handler=${handler.name}]:`, err);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
51
78
|
function catchAsyncResult(result, handlerName, signal, logger) {
|
|
52
79
|
if (result && typeof result.then === "function") {
|
|
53
80
|
return result.catch((err) => {
|
|
@@ -15678,31 +15705,39 @@ var EventBuffer = class {
|
|
|
15678
15705
|
break;
|
|
15679
15706
|
}
|
|
15680
15707
|
}
|
|
15681
|
-
/** Re-add failed create events to the buffer,
|
|
15708
|
+
/** Re-add failed create events to the buffer, returning events that exceed max retries. */
|
|
15682
15709
|
reAddCreates(events) {
|
|
15683
15710
|
const retryable = [];
|
|
15711
|
+
const dropped = [];
|
|
15684
15712
|
for (const e of events) {
|
|
15685
15713
|
if (++e.retryCount <= this.#maxRetries) {
|
|
15686
15714
|
retryable.push(e);
|
|
15715
|
+
} else {
|
|
15716
|
+
dropped.push(e);
|
|
15687
15717
|
}
|
|
15688
15718
|
}
|
|
15689
15719
|
if (retryable.length > 0) {
|
|
15690
15720
|
this.setFirstEventTime();
|
|
15691
15721
|
this.#creates.push(...retryable);
|
|
15692
15722
|
}
|
|
15723
|
+
return dropped;
|
|
15693
15724
|
}
|
|
15694
|
-
/** Re-add failed update events to the buffer,
|
|
15725
|
+
/** Re-add failed update events to the buffer, returning events that exceed max retries. */
|
|
15695
15726
|
reAddUpdates(events) {
|
|
15696
15727
|
const retryable = [];
|
|
15728
|
+
const dropped = [];
|
|
15697
15729
|
for (const e of events) {
|
|
15698
15730
|
if (++e.retryCount <= this.#maxRetries) {
|
|
15699
15731
|
retryable.push(e);
|
|
15732
|
+
} else {
|
|
15733
|
+
dropped.push(e);
|
|
15700
15734
|
}
|
|
15701
15735
|
}
|
|
15702
15736
|
if (retryable.length > 0) {
|
|
15703
15737
|
this.setFirstEventTime();
|
|
15704
15738
|
this.#updates.push(...retryable);
|
|
15705
15739
|
}
|
|
15740
|
+
return dropped;
|
|
15706
15741
|
}
|
|
15707
15742
|
/** Snapshot of buffered create events. */
|
|
15708
15743
|
get creates() {
|
|
@@ -15781,6 +15816,7 @@ var DefaultExporter = class extends BaseExporter {
|
|
|
15781
15816
|
#observabilityStorage;
|
|
15782
15817
|
#resolvedStrategy;
|
|
15783
15818
|
#flushTimer;
|
|
15819
|
+
#emitDropEvent;
|
|
15784
15820
|
// Signals whose storage methods threw "not implemented" — skip on future flushes
|
|
15785
15821
|
#unsupportedSignals = /* @__PURE__ */ new Set();
|
|
15786
15822
|
constructor(config2 = {}) {
|
|
@@ -15802,6 +15838,7 @@ var DefaultExporter = class extends BaseExporter {
|
|
|
15802
15838
|
async init(options) {
|
|
15803
15839
|
try {
|
|
15804
15840
|
this.#isInitializing = true;
|
|
15841
|
+
this.#emitDropEvent = options.emitDropEvent;
|
|
15805
15842
|
this.#storage = options.mastra?.getStorage();
|
|
15806
15843
|
if (!this.#storage) {
|
|
15807
15844
|
this.logger.warn("DefaultExporter disabled: Storage not available. Traces will not be persisted.");
|
|
@@ -15887,21 +15924,54 @@ var DefaultExporter = class extends BaseExporter {
|
|
|
15887
15924
|
this.scheduleFlush();
|
|
15888
15925
|
}
|
|
15889
15926
|
}
|
|
15927
|
+
sanitizeDropError(error48) {
|
|
15928
|
+
if (error48 instanceof MastraError) {
|
|
15929
|
+
return {
|
|
15930
|
+
id: error48.id,
|
|
15931
|
+
domain: String(error48.domain),
|
|
15932
|
+
message: error48.message
|
|
15933
|
+
};
|
|
15934
|
+
}
|
|
15935
|
+
if (error48 instanceof Error) {
|
|
15936
|
+
return { message: error48.message };
|
|
15937
|
+
}
|
|
15938
|
+
return { message: String(error48) };
|
|
15939
|
+
}
|
|
15940
|
+
emitDrop(signal, reason, count, error48) {
|
|
15941
|
+
if (count === 0) return;
|
|
15942
|
+
const dropEvent = {
|
|
15943
|
+
type: "drop",
|
|
15944
|
+
signal,
|
|
15945
|
+
reason,
|
|
15946
|
+
count,
|
|
15947
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
15948
|
+
exporterName: this.name,
|
|
15949
|
+
...this.#observabilityStorage ? { storageName: this.#observabilityStorage.constructor.name } : {},
|
|
15950
|
+
...error48 === void 0 ? {} : { error: this.sanitizeDropError(error48) }
|
|
15951
|
+
};
|
|
15952
|
+
this.#emitDropEvent?.(dropEvent);
|
|
15953
|
+
}
|
|
15890
15954
|
/**
|
|
15891
15955
|
* Flush a batch of create events for a single signal type.
|
|
15892
15956
|
* On "not implemented" errors, disables the signal for future flushes.
|
|
15893
15957
|
* On other errors, re-adds events to the buffer for retry.
|
|
15894
15958
|
*/
|
|
15895
15959
|
async flushCreates(signal, events, storageCall) {
|
|
15896
|
-
if (
|
|
15960
|
+
if (events.length === 0) return;
|
|
15961
|
+
if (this.#unsupportedSignals.has(signal)) {
|
|
15962
|
+
this.emitDrop(signal, "unsupported-storage", events.length);
|
|
15963
|
+
return;
|
|
15964
|
+
}
|
|
15897
15965
|
try {
|
|
15898
15966
|
await storageCall(events);
|
|
15899
15967
|
} catch (error48) {
|
|
15900
15968
|
if (error48 instanceof MastraError && error48.domain === ErrorDomain.MASTRA_OBSERVABILITY && error48.id.endsWith("_NOT_IMPLEMENTED")) {
|
|
15901
15969
|
this.logger.warn(error48.message);
|
|
15902
15970
|
this.#unsupportedSignals.add(signal);
|
|
15971
|
+
this.emitDrop(signal, "unsupported-storage", events.length, error48);
|
|
15903
15972
|
} else {
|
|
15904
|
-
this.#eventBuffer.reAddCreates(events);
|
|
15973
|
+
const dropped = this.#eventBuffer.reAddCreates(events);
|
|
15974
|
+
this.emitDrop(signal, "retry-exhausted", dropped.length, error48);
|
|
15905
15975
|
}
|
|
15906
15976
|
}
|
|
15907
15977
|
}
|
|
@@ -15910,7 +15980,12 @@ var DefaultExporter = class extends BaseExporter {
|
|
|
15910
15980
|
* When `isEnd` is true, successfully flushed spans are removed from tracking.
|
|
15911
15981
|
*/
|
|
15912
15982
|
async flushSpanUpdates(events, deferredUpdates, isEnd) {
|
|
15913
|
-
|
|
15983
|
+
const deferredCountAtEntry = deferredUpdates.length;
|
|
15984
|
+
if (events.length === 0) return;
|
|
15985
|
+
if (this.#unsupportedSignals.has("tracing")) {
|
|
15986
|
+
this.emitDrop("tracing", "unsupported-storage", events.length);
|
|
15987
|
+
return;
|
|
15988
|
+
}
|
|
15914
15989
|
const partials = [];
|
|
15915
15990
|
for (const event of events) {
|
|
15916
15991
|
const span = event.exportedSpan;
|
|
@@ -15934,9 +16009,12 @@ var DefaultExporter = class extends BaseExporter {
|
|
|
15934
16009
|
if (error48 instanceof MastraError && error48.domain === ErrorDomain.MASTRA_OBSERVABILITY && error48.id.endsWith("_NOT_IMPLEMENTED")) {
|
|
15935
16010
|
this.logger.warn(error48.message);
|
|
15936
16011
|
this.#unsupportedSignals.add("tracing");
|
|
16012
|
+
deferredUpdates.length = 0;
|
|
16013
|
+
this.emitDrop("tracing", "unsupported-storage", events.length + deferredCountAtEntry, error48);
|
|
15937
16014
|
} else {
|
|
15938
16015
|
deferredUpdates.length = 0;
|
|
15939
|
-
this.#eventBuffer.reAddUpdates(events);
|
|
16016
|
+
const dropped = this.#eventBuffer.reAddUpdates(events);
|
|
16017
|
+
this.emitDrop("tracing", "retry-exhausted", dropped.length, error48);
|
|
15940
16018
|
}
|
|
15941
16019
|
}
|
|
15942
16020
|
}
|
|
@@ -16012,17 +16090,17 @@ var DefaultExporter = class extends BaseExporter {
|
|
|
16012
16090
|
(events) => this.#observabilityStorage.batchCreateFeedback({ feedbacks: events.map((f) => buildFeedbackRecord(f)) })
|
|
16013
16091
|
),
|
|
16014
16092
|
this.flushCreates(
|
|
16015
|
-
"
|
|
16093
|
+
"log",
|
|
16016
16094
|
createLogEvents,
|
|
16017
16095
|
(events) => this.#observabilityStorage.batchCreateLogs({ logs: events.map((l) => buildLogRecord(l)) })
|
|
16018
16096
|
),
|
|
16019
16097
|
this.flushCreates(
|
|
16020
|
-
"
|
|
16098
|
+
"metric",
|
|
16021
16099
|
createMetricEvents,
|
|
16022
16100
|
(events) => this.#observabilityStorage.batchCreateMetrics({ metrics: events.map((m) => buildMetricRecord(m)) })
|
|
16023
16101
|
),
|
|
16024
16102
|
this.flushCreates(
|
|
16025
|
-
"
|
|
16103
|
+
"score",
|
|
16026
16104
|
createScoreEvents,
|
|
16027
16105
|
(events) => this.#observabilityStorage.batchCreateScores({ scores: events.map((s) => buildScoreRecord(s)) })
|
|
16028
16106
|
),
|
|
@@ -16036,7 +16114,13 @@ var DefaultExporter = class extends BaseExporter {
|
|
|
16036
16114
|
await this.flushSpanUpdates(updateSpanEvents, deferredUpdates, false);
|
|
16037
16115
|
await this.flushSpanUpdates(endSpanEvents, deferredUpdates, true);
|
|
16038
16116
|
if (deferredUpdates.length > 0) {
|
|
16039
|
-
this.#
|
|
16117
|
+
if (this.#unsupportedSignals.has("tracing")) {
|
|
16118
|
+
this.emitDrop("tracing", "unsupported-storage", deferredUpdates.length);
|
|
16119
|
+
deferredUpdates.length = 0;
|
|
16120
|
+
} else {
|
|
16121
|
+
const dropped = this.#eventBuffer.reAddUpdates(deferredUpdates);
|
|
16122
|
+
this.emitDrop("tracing", "retry-exhausted", dropped.length);
|
|
16123
|
+
}
|
|
16040
16124
|
}
|
|
16041
16125
|
const elapsed = Date.now() - startTime;
|
|
16042
16126
|
this.logger.debug("Batch flushed", {
|
|
@@ -17665,6 +17749,8 @@ var ObservabilityBus = class extends BaseObservabilityEventBus {
|
|
|
17665
17749
|
bridge;
|
|
17666
17750
|
/** In-flight handler promises from routeToHandler. Self-cleaning via .finally(). */
|
|
17667
17751
|
pendingHandlers = /* @__PURE__ */ new Set();
|
|
17752
|
+
handlerBufferFlushDepth = 0;
|
|
17753
|
+
dropEventsEmittedDuringHandlerFlush = 0;
|
|
17668
17754
|
/** Resolved deepClean options applied to non-tracing events before fan-out. */
|
|
17669
17755
|
deepCleanOptions;
|
|
17670
17756
|
constructor(opts) {
|
|
@@ -17751,6 +17837,23 @@ var ObservabilityBus = class extends BaseObservabilityEventBus {
|
|
|
17751
17837
|
}
|
|
17752
17838
|
super.emit(cleaned);
|
|
17753
17839
|
}
|
|
17840
|
+
/**
|
|
17841
|
+
* Emit exporter pipeline drop events to exporters and the bridge.
|
|
17842
|
+
*
|
|
17843
|
+
* Drop events describe exporter health, not user observability data, so they
|
|
17844
|
+
* are intentionally not delivered to generic event-bus subscribers.
|
|
17845
|
+
*/
|
|
17846
|
+
emitDropEvent(event) {
|
|
17847
|
+
if (this.handlerBufferFlushDepth > 0) {
|
|
17848
|
+
this.dropEventsEmittedDuringHandlerFlush++;
|
|
17849
|
+
}
|
|
17850
|
+
for (const exporter of this.exporters) {
|
|
17851
|
+
this.trackPromise(routeDropToHandler(exporter, event, this.logger));
|
|
17852
|
+
}
|
|
17853
|
+
if (this.bridge) {
|
|
17854
|
+
this.trackPromise(routeDropToHandler(this.bridge, event, this.logger));
|
|
17855
|
+
}
|
|
17856
|
+
}
|
|
17754
17857
|
/**
|
|
17755
17858
|
* Track an async handler promise so flush() can await it.
|
|
17756
17859
|
* No-ops for sync (void) results.
|
|
@@ -17762,19 +17865,8 @@ var ObservabilityBus = class extends BaseObservabilityEventBus {
|
|
|
17762
17865
|
void promise2.finally(() => this.pendingHandlers.delete(promise2));
|
|
17763
17866
|
}
|
|
17764
17867
|
}
|
|
17765
|
-
/**
|
|
17766
|
-
|
|
17767
|
-
*
|
|
17768
|
-
* **Phase 1 — Delivery:** Await all in-flight handler promises (exporters,
|
|
17769
|
-
* bridge, and base-class subscribers). After this resolves, all event data
|
|
17770
|
-
* has been delivered to handler methods.
|
|
17771
|
-
*
|
|
17772
|
-
* **Phase 2 — Buffer drain:** Call flush() on each exporter and bridge to
|
|
17773
|
-
* drain their SDK-internal buffers (e.g., OTEL BatchSpanProcessor, Langfuse
|
|
17774
|
-
* client queue). Phases are sequential — Phase 2 must not start until
|
|
17775
|
-
* Phase 1 completes, otherwise exporters would flush empty buffers.
|
|
17776
|
-
*/
|
|
17777
|
-
async flush() {
|
|
17868
|
+
/** Await in-flight routed handler promises, draining until empty. */
|
|
17869
|
+
async drainPendingHandlers() {
|
|
17778
17870
|
let iterations = 0;
|
|
17779
17871
|
while (this.pendingHandlers.size > 0) {
|
|
17780
17872
|
await Promise.allSettled([...this.pendingHandlers]);
|
|
@@ -17789,14 +17881,54 @@ var ObservabilityBus = class extends BaseObservabilityEventBus {
|
|
|
17789
17881
|
break;
|
|
17790
17882
|
}
|
|
17791
17883
|
}
|
|
17792
|
-
|
|
17793
|
-
|
|
17794
|
-
|
|
17795
|
-
|
|
17884
|
+
}
|
|
17885
|
+
/** Drain exporter and bridge SDK-internal buffers. */
|
|
17886
|
+
async flushHandlerBuffers() {
|
|
17887
|
+
const initialDropCount = this.dropEventsEmittedDuringHandlerFlush;
|
|
17888
|
+
this.handlerBufferFlushDepth++;
|
|
17889
|
+
try {
|
|
17890
|
+
const bufferFlushPromises = this.exporters.map((e) => e.flush());
|
|
17891
|
+
if (this.bridge) {
|
|
17892
|
+
bufferFlushPromises.push(this.bridge.flush());
|
|
17893
|
+
}
|
|
17894
|
+
if (bufferFlushPromises.length > 0) {
|
|
17895
|
+
await Promise.allSettled(bufferFlushPromises);
|
|
17896
|
+
}
|
|
17897
|
+
return this.dropEventsEmittedDuringHandlerFlush > initialDropCount;
|
|
17898
|
+
} finally {
|
|
17899
|
+
this.handlerBufferFlushDepth--;
|
|
17796
17900
|
}
|
|
17797
|
-
|
|
17798
|
-
|
|
17901
|
+
}
|
|
17902
|
+
/**
|
|
17903
|
+
* Multi-phase flush to ensure all observability data is fully exported.
|
|
17904
|
+
*
|
|
17905
|
+
* **Phase 1 — Delivery:** Await all in-flight handler promises (exporters,
|
|
17906
|
+
* bridge, and base-class subscribers). After this resolves, all event data
|
|
17907
|
+
* has been delivered to handler methods.
|
|
17908
|
+
*
|
|
17909
|
+
* **Phase 2 — Buffer drain:** Call flush() on each exporter and bridge to
|
|
17910
|
+
* drain their SDK-internal buffers (e.g., OTEL BatchSpanProcessor, Langfuse
|
|
17911
|
+
* client queue). Phases are sequential — buffer drains must not start until
|
|
17912
|
+
* delivery completes, otherwise exporters would flush empty buffers.
|
|
17913
|
+
*
|
|
17914
|
+
* Exporter flushes can emit drop events. When that happens, flush loops
|
|
17915
|
+
* through delivery and buffer drain again so alerting integrations that buffer
|
|
17916
|
+
* drop notifications are drained before returning.
|
|
17917
|
+
*/
|
|
17918
|
+
async flush() {
|
|
17919
|
+
await this.drainPendingHandlers();
|
|
17920
|
+
await super.flush();
|
|
17921
|
+
for (let iterations = 0; iterations < MAX_FLUSH_ITERATIONS; iterations++) {
|
|
17922
|
+
const emittedDropEvents = await this.flushHandlerBuffers();
|
|
17923
|
+
if (!emittedDropEvents && this.pendingHandlers.size === 0) {
|
|
17924
|
+
return;
|
|
17925
|
+
}
|
|
17926
|
+
await this.drainPendingHandlers();
|
|
17927
|
+
await super.flush();
|
|
17799
17928
|
}
|
|
17929
|
+
this.logger.error(
|
|
17930
|
+
`[ObservabilityBus] flush() exceeded ${MAX_FLUSH_ITERATIONS} buffer drain iterations. Handlers may be emitting drop events during every flush.`
|
|
17931
|
+
);
|
|
17800
17932
|
}
|
|
17801
17933
|
/** Flush all pending events and exporter buffers, then clear subscribers. */
|
|
17802
17934
|
async shutdown() {
|
|
@@ -18155,8 +18287,19 @@ function normalizeProvider(provider) {
|
|
|
18155
18287
|
return dotIndex !== -1 ? normalized.substring(0, dotIndex) : normalized;
|
|
18156
18288
|
}
|
|
18157
18289
|
function getModelVariants(model) {
|
|
18158
|
-
const
|
|
18159
|
-
|
|
18290
|
+
const variants = /* @__PURE__ */ new Set();
|
|
18291
|
+
const add = (v) => {
|
|
18292
|
+
variants.add(v);
|
|
18293
|
+
variants.add(stripDateSuffix(v));
|
|
18294
|
+
};
|
|
18295
|
+
add(model);
|
|
18296
|
+
add(model.replace(/\./g, "-"));
|
|
18297
|
+
add(model.replace(/[./]/g, "-"));
|
|
18298
|
+
const slashIndex = model.indexOf("/");
|
|
18299
|
+
if (slashIndex !== -1) {
|
|
18300
|
+
add(model.substring(slashIndex + 1));
|
|
18301
|
+
}
|
|
18302
|
+
return [...variants];
|
|
18160
18303
|
}
|
|
18161
18304
|
function stripDateSuffix(model) {
|
|
18162
18305
|
let stripped = model.replace(/-20\d{2}-\d{2}-\d{2}$/, "");
|
|
@@ -18599,6 +18742,9 @@ function sumDefinedValues(obj, keys) {
|
|
|
18599
18742
|
}
|
|
18600
18743
|
|
|
18601
18744
|
// src/model-tracing.ts
|
|
18745
|
+
function supportsModelInference() {
|
|
18746
|
+
return coreFeatures.has("model-inference-span");
|
|
18747
|
+
}
|
|
18602
18748
|
function formatPreviewLabel(label, fallback) {
|
|
18603
18749
|
return typeof label === "string" && label.length > 0 ? label : fallback;
|
|
18604
18750
|
}
|
|
@@ -18757,6 +18903,7 @@ function extractStepInput(payload) {
|
|
|
18757
18903
|
var ModelSpanTracker = class {
|
|
18758
18904
|
#modelSpan;
|
|
18759
18905
|
#currentStepSpan;
|
|
18906
|
+
#currentInferenceSpan;
|
|
18760
18907
|
#currentChunkSpan;
|
|
18761
18908
|
#currentChunkType;
|
|
18762
18909
|
#accumulator = {};
|
|
@@ -18768,9 +18915,18 @@ var ModelSpanTracker = class {
|
|
|
18768
18915
|
#deferStepClose = false;
|
|
18769
18916
|
/** Stored step-finish payload when defer mode is enabled */
|
|
18770
18917
|
#pendingStepFinishPayload;
|
|
18918
|
+
/** Static request-side context applied to every MODEL_INFERENCE span */
|
|
18919
|
+
#inferenceContext;
|
|
18771
18920
|
constructor(modelSpan) {
|
|
18772
18921
|
this.#modelSpan = modelSpan;
|
|
18773
18922
|
}
|
|
18923
|
+
/**
|
|
18924
|
+
* Set request-side context applied to subsequent MODEL_INFERENCE spans.
|
|
18925
|
+
* No-op when paired with an older @mastra/core that lacks the feature flag.
|
|
18926
|
+
*/
|
|
18927
|
+
setInferenceContext(context) {
|
|
18928
|
+
this.#inferenceContext = context;
|
|
18929
|
+
}
|
|
18774
18930
|
/**
|
|
18775
18931
|
* Capture the completion start time (time to first token) when the first content chunk arrives.
|
|
18776
18932
|
*/
|
|
@@ -18852,6 +19008,11 @@ var ModelSpanTracker = class {
|
|
|
18852
19008
|
* Start a new Model execution step.
|
|
18853
19009
|
* This should be called at the beginning of LLM execution to capture accurate startTime.
|
|
18854
19010
|
* The step-start chunk payload can be passed later via updateStep() if needed.
|
|
19011
|
+
*
|
|
19012
|
+
* Note: this only opens MODEL_STEP. The MODEL_INFERENCE child span is opened
|
|
19013
|
+
* separately via startInference() so its duration excludes input processor work.
|
|
19014
|
+
* Callers that don't call startInference() explicitly will get one auto-created
|
|
19015
|
+
* when the first model chunk arrives.
|
|
18855
19016
|
*/
|
|
18856
19017
|
startStep(payload) {
|
|
18857
19018
|
if (this.#currentStepSpan) {
|
|
@@ -18871,6 +19032,71 @@ var ModelSpanTracker = class {
|
|
|
18871
19032
|
this.#currentStepInputIsFinal = Array.isArray(payload?.inputMessages);
|
|
18872
19033
|
this.#chunkSequence = 0;
|
|
18873
19034
|
}
|
|
19035
|
+
/**
|
|
19036
|
+
* End the current MODEL_INFERENCE span when the provider stream finishes.
|
|
19037
|
+
* Fields are duplicated onto MODEL_STEP (in #endStepSpan) so existing
|
|
19038
|
+
* integrations that read usage/finishReason from the step span continue
|
|
19039
|
+
* to work unchanged.
|
|
19040
|
+
*
|
|
19041
|
+
* Safe to call multiple times - no-ops if the span is already closed.
|
|
19042
|
+
*/
|
|
19043
|
+
#endInferenceSpan(payload) {
|
|
19044
|
+
if (!this.#currentInferenceSpan) return;
|
|
19045
|
+
const { usage: rawUsage, ...otherOutput } = payload.output;
|
|
19046
|
+
const usage = extractUsageMetrics(rawUsage, payload.metadata?.providerMetadata);
|
|
19047
|
+
this.#currentInferenceSpan.end({
|
|
19048
|
+
output: otherOutput,
|
|
19049
|
+
attributes: {
|
|
19050
|
+
usage,
|
|
19051
|
+
finishReason: payload.stepResult.reason,
|
|
19052
|
+
warnings: payload.stepResult.warnings,
|
|
19053
|
+
completionStartTime: this.#completionStartTime
|
|
19054
|
+
}
|
|
19055
|
+
});
|
|
19056
|
+
this.#currentInferenceSpan = void 0;
|
|
19057
|
+
}
|
|
19058
|
+
/**
|
|
19059
|
+
* Open the MODEL_INFERENCE span for the current step. Chunks (including tool-call
|
|
19060
|
+
* chunks emitted by the model) parent under this span so its duration reflects
|
|
19061
|
+
* pure model latency.
|
|
19062
|
+
*
|
|
19063
|
+
* Should be called immediately before invoking the model — after any input
|
|
19064
|
+
* processors / `prepareStep` work has completed — so the span's startTime
|
|
19065
|
+
* does not include processor time. The latest `#inferenceContext` (set via
|
|
19066
|
+
* setInferenceContext) is snapshotted onto the span at creation.
|
|
19067
|
+
*
|
|
19068
|
+
* No-ops when the installed @mastra/core lacks the `model-inference-span`
|
|
19069
|
+
* feature flag, or when called without an active step span. Auto-invoked from
|
|
19070
|
+
* chunk handlers as a safety net; explicit callers get the most accurate
|
|
19071
|
+
* start time.
|
|
19072
|
+
*/
|
|
19073
|
+
startInference(payload) {
|
|
19074
|
+
if (!supportsModelInference()) {
|
|
19075
|
+
return;
|
|
19076
|
+
}
|
|
19077
|
+
if (!this.#currentStepSpan || this.#currentInferenceSpan) {
|
|
19078
|
+
return;
|
|
19079
|
+
}
|
|
19080
|
+
const input = extractStepInput(payload);
|
|
19081
|
+
const generationAttrs = this.#modelSpan?.attributes;
|
|
19082
|
+
const ctx = this.#inferenceContext;
|
|
19083
|
+
this.#currentInferenceSpan = this.#currentStepSpan.createChildSpan({
|
|
19084
|
+
name: `inference: ${this.#stepIndex}`,
|
|
19085
|
+
type: SpanType.MODEL_INFERENCE,
|
|
19086
|
+
attributes: {
|
|
19087
|
+
stepIndex: this.#stepIndex,
|
|
19088
|
+
model: generationAttrs?.model,
|
|
19089
|
+
provider: generationAttrs?.provider,
|
|
19090
|
+
streaming: generationAttrs?.streaming,
|
|
19091
|
+
...ctx?.parameters !== void 0 ? { parameters: ctx.parameters } : {},
|
|
19092
|
+
...ctx?.providerOptions !== void 0 ? { providerOptions: ctx.providerOptions } : {},
|
|
19093
|
+
...ctx?.availableTools !== void 0 ? { availableTools: ctx.availableTools } : {},
|
|
19094
|
+
...ctx?.toolChoice !== void 0 ? { toolChoice: ctx.toolChoice } : {},
|
|
19095
|
+
...ctx?.responseFormat !== void 0 ? { responseFormat: ctx.responseFormat } : {}
|
|
19096
|
+
},
|
|
19097
|
+
input
|
|
19098
|
+
});
|
|
19099
|
+
}
|
|
18874
19100
|
/**
|
|
18875
19101
|
* Update the current step span with additional payload data.
|
|
18876
19102
|
* Called when step-start chunk arrives with request/warnings info.
|
|
@@ -18909,6 +19135,7 @@ var ModelSpanTracker = class {
|
|
|
18909
19135
|
delete cleanMetadata[key];
|
|
18910
19136
|
}
|
|
18911
19137
|
}
|
|
19138
|
+
this.#endInferenceSpan(payload);
|
|
18912
19139
|
this.#currentStepSpan.end({
|
|
18913
19140
|
output: otherOutput,
|
|
18914
19141
|
attributes: {
|
|
@@ -18926,14 +19153,35 @@ var ModelSpanTracker = class {
|
|
|
18926
19153
|
this.#stepIndex++;
|
|
18927
19154
|
}
|
|
18928
19155
|
/**
|
|
18929
|
-
*
|
|
19156
|
+
* Returns the parent span for chunks. Chunks parent under MODEL_INFERENCE
|
|
19157
|
+
* (the provider call) when available, falling back to MODEL_STEP only if
|
|
19158
|
+
* startStep() was bypassed.
|
|
18930
19159
|
*/
|
|
18931
|
-
#
|
|
18932
|
-
this.#
|
|
19160
|
+
#chunkParent() {
|
|
19161
|
+
return this.#currentInferenceSpan ?? this.#currentStepSpan;
|
|
19162
|
+
}
|
|
19163
|
+
/**
|
|
19164
|
+
* Safety-net invoked from chunk handlers: auto-create MODEL_STEP and
|
|
19165
|
+
* MODEL_INFERENCE if a chunk arrives before the loop has explicitly opened
|
|
19166
|
+
* them, so chunks parent under MODEL_INFERENCE rather than falling through
|
|
19167
|
+
* to MODEL_STEP. Idempotent — each public start* method is itself a no-op
|
|
19168
|
+
* when its span is already live.
|
|
19169
|
+
*/
|
|
19170
|
+
#ensureStepAndInference() {
|
|
18933
19171
|
if (!this.#currentStepSpan) {
|
|
18934
19172
|
this.startStep();
|
|
18935
19173
|
}
|
|
18936
|
-
this.#
|
|
19174
|
+
if (!this.#currentInferenceSpan) {
|
|
19175
|
+
this.startInference();
|
|
19176
|
+
}
|
|
19177
|
+
}
|
|
19178
|
+
/**
|
|
19179
|
+
* Create a new chunk span (for multi-part chunks like text-start/delta/end)
|
|
19180
|
+
*/
|
|
19181
|
+
#startChunkSpan(chunkType, initialData) {
|
|
19182
|
+
this.#endChunkSpan();
|
|
19183
|
+
this.#ensureStepAndInference();
|
|
19184
|
+
this.#currentChunkSpan = this.#chunkParent()?.createChildSpan({
|
|
18937
19185
|
name: `chunk: '${chunkType}'`,
|
|
18938
19186
|
type: SpanType.MODEL_CHUNK,
|
|
18939
19187
|
attributes: {
|
|
@@ -18972,10 +19220,8 @@ var ModelSpanTracker = class {
|
|
|
18972
19220
|
* Create an event span (for single chunks like tool-call)
|
|
18973
19221
|
*/
|
|
18974
19222
|
#createEventSpan(chunkType, output, options) {
|
|
18975
|
-
|
|
18976
|
-
|
|
18977
|
-
}
|
|
18978
|
-
const span = this.#currentStepSpan?.createEventSpan({
|
|
19223
|
+
this.#ensureStepAndInference();
|
|
19224
|
+
const span = this.#chunkParent()?.createEventSpan({
|
|
18979
19225
|
name: `chunk: '${chunkType}'`,
|
|
18980
19226
|
type: SpanType.MODEL_CHUNK,
|
|
18981
19227
|
attributes: {
|
|
@@ -19096,10 +19342,8 @@ var ModelSpanTracker = class {
|
|
|
19096
19342
|
#handleToolApprovalChunk(chunk) {
|
|
19097
19343
|
if (chunk.type !== "tool-call-approval") return;
|
|
19098
19344
|
const payload = chunk.payload;
|
|
19099
|
-
|
|
19100
|
-
|
|
19101
|
-
}
|
|
19102
|
-
const span = this.#currentStepSpan?.createEventSpan({
|
|
19345
|
+
this.#ensureStepAndInference();
|
|
19346
|
+
const span = this.#chunkParent()?.createEventSpan({
|
|
19103
19347
|
name: `chunk: 'tool-call-approval'`,
|
|
19104
19348
|
type: SpanType.MODEL_CHUNK,
|
|
19105
19349
|
attributes: {
|
|
@@ -19157,10 +19401,15 @@ var ModelSpanTracker = class {
|
|
|
19157
19401
|
} else {
|
|
19158
19402
|
this.startStep(chunk.payload);
|
|
19159
19403
|
}
|
|
19404
|
+
if (!this.#currentInferenceSpan) {
|
|
19405
|
+
this.startInference(chunk.payload);
|
|
19406
|
+
}
|
|
19160
19407
|
break;
|
|
19161
19408
|
case "step-finish":
|
|
19162
19409
|
if (this.#deferStepClose) {
|
|
19163
19410
|
this.#pendingStepFinishPayload = chunk.payload;
|
|
19411
|
+
this.#endChunkSpan();
|
|
19412
|
+
this.#endInferenceSpan(chunk.payload);
|
|
19164
19413
|
} else {
|
|
19165
19414
|
this.#endStepSpan(chunk.payload);
|
|
19166
19415
|
}
|
|
@@ -19256,6 +19505,7 @@ function isSpanInternal(spanType, flags) {
|
|
|
19256
19505
|
// Model-related spans
|
|
19257
19506
|
case SpanType.MODEL_GENERATION:
|
|
19258
19507
|
case SpanType.MODEL_STEP:
|
|
19508
|
+
case SpanType.MODEL_INFERENCE:
|
|
19259
19509
|
case SpanType.MODEL_CHUNK:
|
|
19260
19510
|
return (flags & InternalSpans.MODEL) !== 0;
|
|
19261
19511
|
// Default: never internal
|
|
@@ -20348,6 +20598,7 @@ function buildScoreEvent(args) {
|
|
|
20348
20598
|
traceId,
|
|
20349
20599
|
spanId,
|
|
20350
20600
|
scorerId: score.scorerId,
|
|
20601
|
+
scorerName: score.scorerName,
|
|
20351
20602
|
scorerVersion: score.scorerVersion,
|
|
20352
20603
|
source: score.source,
|
|
20353
20604
|
scoreSource: score.scoreSource,
|
|
@@ -20355,6 +20606,7 @@ function buildScoreEvent(args) {
|
|
|
20355
20606
|
reason: score.reason,
|
|
20356
20607
|
experimentId: score.experimentId,
|
|
20357
20608
|
scoreTraceId: score.scoreTraceId,
|
|
20609
|
+
targetEntityType: score.targetEntityType,
|
|
20358
20610
|
correlationContext,
|
|
20359
20611
|
metadata: mergeMetadata(inheritedMetadata, score.metadata)
|
|
20360
20612
|
}
|
|
@@ -20953,10 +21205,11 @@ var Observability = class extends MastraBase {
|
|
|
20953
21205
|
instance.__setMastraEnvironment?.(mastraEnvironment);
|
|
20954
21206
|
const config2 = instance.getConfig();
|
|
20955
21207
|
const exporters = instance.getExporters();
|
|
21208
|
+
const emitDropEvent = instance instanceof BaseObservabilityInstance ? (event) => instance.getObservabilityBus().emitDropEvent(event) : void 0;
|
|
20956
21209
|
exporters.forEach((exporter) => {
|
|
20957
21210
|
if ("init" in exporter && typeof exporter.init === "function") {
|
|
20958
21211
|
try {
|
|
20959
|
-
exporter.init({ mastra, config: config2 });
|
|
21212
|
+
exporter.init({ mastra, config: config2, emitDropEvent });
|
|
20960
21213
|
} catch (error48) {
|
|
20961
21214
|
this.logger?.warn("Failed to initialize observability exporter", {
|
|
20962
21215
|
exporterName: exporter.name,
|
|
@@ -21144,11 +21397,14 @@ var Observability = class extends MastraBase {
|
|
|
21144
21397
|
}
|
|
21145
21398
|
};
|
|
21146
21399
|
|
|
21400
|
+
// src/features.ts
|
|
21401
|
+
var observabilityFeatures = /* @__PURE__ */ new Set(["model-inference-span"]);
|
|
21402
|
+
|
|
21147
21403
|
// src/tracing-options.ts
|
|
21148
21404
|
function buildTracingOptions(...updaters) {
|
|
21149
21405
|
return updaters.reduce((opts, updater) => updater(opts), {});
|
|
21150
21406
|
}
|
|
21151
21407
|
|
|
21152
|
-
export { BaseExporter, BaseObservabilityEventBus, BaseObservabilityInstance, BaseSpan, CardinalityFilter, CloudExporter, ConsoleExporter, DEFAULT_DEEP_CLEAN_OPTIONS, DEFAULT_KEYS_TO_STRIP, DefaultExporter, DefaultObservabilityInstance, DefaultSpan, JsonExporter, LoggerContextImpl, MetricsContextImpl, ModelSpanTracker, NoOpSpan, Observability, ObservabilityBus, SamplingStrategyType, SensitiveDataFilter, TestExporter, TraceData, TrackingExporter, buildTracingOptions, chainFormatters, deepClean, getExternalParentId, isSerializedMap, mergeSerializationOptions, observabilityConfigValueSchema, observabilityInstanceConfigSchema, observabilityRegistryConfigSchema, reconstructSerializedMap, routeToHandler, samplingStrategySchema, serializationOptionsSchema, truncateString };
|
|
21408
|
+
export { BaseExporter, BaseObservabilityEventBus, BaseObservabilityInstance, BaseSpan, CardinalityFilter, CloudExporter, ConsoleExporter, DEFAULT_DEEP_CLEAN_OPTIONS, DEFAULT_KEYS_TO_STRIP, DefaultExporter, DefaultObservabilityInstance, DefaultSpan, JsonExporter, LoggerContextImpl, MetricsContextImpl, ModelSpanTracker, NoOpSpan, Observability, ObservabilityBus, SamplingStrategyType, SensitiveDataFilter, TestExporter, TraceData, TrackingExporter, buildTracingOptions, chainFormatters, deepClean, getExternalParentId, isSerializedMap, mergeSerializationOptions, observabilityConfigValueSchema, observabilityFeatures, observabilityInstanceConfigSchema, observabilityRegistryConfigSchema, reconstructSerializedMap, routeToHandler, samplingStrategySchema, serializationOptionsSchema, truncateString };
|
|
21153
21409
|
//# sourceMappingURL=index.js.map
|
|
21154
21410
|
//# sourceMappingURL=index.js.map
|