@mastra/observability 1.7.3 → 1.8.0-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.js CHANGED
@@ -15026,18 +15026,144 @@ function chainFormatters(formatters) {
15026
15026
  return currentSpan;
15027
15027
  };
15028
15028
  }
15029
+ var SIGNAL_PUBLISH_SUFFIXES = {
15030
+ traces: "/spans/publish",
15031
+ logs: "/logs/publish",
15032
+ metrics: "/metrics/publish",
15033
+ scores: "/scores/publish",
15034
+ feedback: "/feedback/publish"
15035
+ };
15036
+ var SIGNAL_PUBLISH_PATHS = {
15037
+ traces: "/ai/spans/publish",
15038
+ logs: "/ai/logs/publish",
15039
+ metrics: "/ai/metrics/publish",
15040
+ scores: "/ai/scores/publish",
15041
+ feedback: "/ai/feedback/publish"
15042
+ };
15043
+ var SIGNAL_PAYLOAD_KEYS = {
15044
+ traces: "spans",
15045
+ logs: "logs",
15046
+ metrics: "metrics",
15047
+ scores: "scores",
15048
+ feedback: "feedback"
15049
+ };
15050
+ var DEFAULT_CLOUD_ENDPOINT = "https://api.mastra.ai";
15051
+ function trimTrailingSlashes(value) {
15052
+ let end = value.length;
15053
+ while (end > 0 && value.charCodeAt(end - 1) === 47) {
15054
+ end--;
15055
+ }
15056
+ return end === value.length ? value : value.slice(0, end);
15057
+ }
15058
+ function createInvalidEndpointError(endpoint, text, cause) {
15059
+ return new MastraError(
15060
+ {
15061
+ id: `CLOUD_EXPORTER_INVALID_ENDPOINT`,
15062
+ text,
15063
+ domain: ErrorDomain.MASTRA_OBSERVABILITY,
15064
+ category: ErrorCategory.USER,
15065
+ details: {
15066
+ endpoint
15067
+ }
15068
+ },
15069
+ cause
15070
+ );
15071
+ }
15072
+ function resolveBaseEndpoint(baseEndpoint) {
15073
+ const normalizedEndpoint = trimTrailingSlashes(baseEndpoint);
15074
+ const invalidText = 'CloudExporter endpoint must be a base origin like "https://collector.example.com" with no path, search, or hash.';
15075
+ try {
15076
+ const parsedEndpoint = new URL(normalizedEndpoint);
15077
+ if (parsedEndpoint.pathname !== "/" || parsedEndpoint.search || parsedEndpoint.hash) {
15078
+ throw createInvalidEndpointError(baseEndpoint, invalidText);
15079
+ }
15080
+ return trimTrailingSlashes(parsedEndpoint.origin);
15081
+ } catch (error48) {
15082
+ if (error48 instanceof MastraError) {
15083
+ throw error48;
15084
+ }
15085
+ throw createInvalidEndpointError(baseEndpoint, invalidText, error48);
15086
+ }
15087
+ }
15088
+ function buildSignalEndpoint(baseEndpoint, signal) {
15089
+ return `${baseEndpoint}${SIGNAL_PUBLISH_PATHS[signal]}`;
15090
+ }
15091
+ function resolveExplicitSignalEndpoint(signal, endpoint) {
15092
+ const normalizedEndpoint = trimTrailingSlashes(endpoint);
15093
+ const invalidText = `CloudExporter ${signal}Endpoint must be a base origin like "https://collector.example.com" or a full ${signal} publish URL ending in "${SIGNAL_PUBLISH_SUFFIXES[signal]}".`;
15094
+ try {
15095
+ const parsedEndpoint = new URL(normalizedEndpoint);
15096
+ if (parsedEndpoint.search || parsedEndpoint.hash) {
15097
+ throw createInvalidEndpointError(endpoint, invalidText);
15098
+ }
15099
+ const normalizedOrigin = trimTrailingSlashes(parsedEndpoint.origin);
15100
+ const normalizedPathname = trimTrailingSlashes(parsedEndpoint.pathname);
15101
+ if (!normalizedPathname || normalizedPathname === "/") {
15102
+ return buildSignalEndpoint(normalizedOrigin, signal);
15103
+ }
15104
+ if (normalizedPathname.endsWith(SIGNAL_PUBLISH_SUFFIXES[signal])) {
15105
+ return `${normalizedOrigin}${normalizedPathname}`;
15106
+ }
15107
+ throw createInvalidEndpointError(endpoint, invalidText);
15108
+ } catch (error48) {
15109
+ if (error48 instanceof MastraError) {
15110
+ throw error48;
15111
+ }
15112
+ throw createInvalidEndpointError(endpoint, invalidText, error48);
15113
+ }
15114
+ }
15115
+ function deriveSignalEndpointFromTracesEndpoint(signal, tracesEndpoint) {
15116
+ if (signal === "traces") {
15117
+ return tracesEndpoint;
15118
+ }
15119
+ const normalizedTracesEndpoint = trimTrailingSlashes(tracesEndpoint);
15120
+ const invalidText = 'CloudExporter tracesEndpoint must be a base origin like "https://collector.example.com" or a full traces publish URL ending in "/spans/publish".';
15121
+ try {
15122
+ const parsedEndpoint = new URL(normalizedTracesEndpoint);
15123
+ const normalizedOrigin = trimTrailingSlashes(parsedEndpoint.origin);
15124
+ const normalizedPathname = trimTrailingSlashes(parsedEndpoint.pathname);
15125
+ if (!normalizedPathname.endsWith(SIGNAL_PUBLISH_SUFFIXES.traces)) {
15126
+ throw createInvalidEndpointError(tracesEndpoint, invalidText);
15127
+ }
15128
+ const basePath = normalizedPathname.slice(0, -SIGNAL_PUBLISH_SUFFIXES.traces.length);
15129
+ return `${normalizedOrigin}${basePath}${SIGNAL_PUBLISH_SUFFIXES[signal]}`;
15130
+ } catch (error48) {
15131
+ if (error48 instanceof MastraError) {
15132
+ throw error48;
15133
+ }
15134
+ throw createInvalidEndpointError(tracesEndpoint, invalidText, error48);
15135
+ }
15136
+ }
15029
15137
  var CloudExporter = class extends BaseExporter {
15030
15138
  name = "mastra-cloud-observability-exporter";
15031
15139
  cloudConfig;
15032
15140
  buffer;
15033
15141
  flushTimer = null;
15142
+ inFlightFlushes = /* @__PURE__ */ new Set();
15034
15143
  constructor(config2 = {}) {
15035
15144
  super(config2);
15036
15145
  const accessToken = config2.accessToken ?? process.env.MASTRA_CLOUD_ACCESS_TOKEN;
15037
15146
  if (!accessToken) {
15038
15147
  this.setDisabled("MASTRA_CLOUD_ACCESS_TOKEN environment variable not set.");
15039
15148
  }
15040
- const endpoint = config2.endpoint ?? process.env.MASTRA_CLOUD_TRACES_ENDPOINT ?? "https://api.mastra.ai/ai/spans/publish";
15149
+ const tracesEndpointOverride = config2.tracesEndpoint ?? process.env.MASTRA_CLOUD_TRACES_ENDPOINT;
15150
+ let baseEndpoint;
15151
+ let tracesEndpoint;
15152
+ if (tracesEndpointOverride) {
15153
+ tracesEndpoint = resolveExplicitSignalEndpoint("traces", tracesEndpointOverride);
15154
+ } else {
15155
+ baseEndpoint = resolveBaseEndpoint(config2.endpoint ?? DEFAULT_CLOUD_ENDPOINT);
15156
+ tracesEndpoint = buildSignalEndpoint(baseEndpoint, "traces");
15157
+ }
15158
+ const resolveConfiguredSignalEndpoint = (signal, explicitEndpoint) => {
15159
+ if (explicitEndpoint) {
15160
+ return resolveExplicitSignalEndpoint(signal, explicitEndpoint);
15161
+ }
15162
+ if (tracesEndpointOverride) {
15163
+ return deriveSignalEndpointFromTracesEndpoint(signal, tracesEndpoint);
15164
+ }
15165
+ return buildSignalEndpoint(baseEndpoint, signal);
15166
+ };
15041
15167
  this.cloudConfig = {
15042
15168
  logger: this.logger,
15043
15169
  logLevel: config2.logLevel ?? LogLevel.INFO,
@@ -15045,10 +15171,18 @@ var CloudExporter = class extends BaseExporter {
15045
15171
  maxBatchWaitMs: config2.maxBatchWaitMs ?? 5e3,
15046
15172
  maxRetries: config2.maxRetries ?? 3,
15047
15173
  accessToken: accessToken || "",
15048
- endpoint
15174
+ tracesEndpoint,
15175
+ logsEndpoint: resolveConfiguredSignalEndpoint("logs", config2.logsEndpoint),
15176
+ metricsEndpoint: resolveConfiguredSignalEndpoint("metrics", config2.metricsEndpoint),
15177
+ scoresEndpoint: resolveConfiguredSignalEndpoint("scores", config2.scoresEndpoint),
15178
+ feedbackEndpoint: resolveConfiguredSignalEndpoint("feedback", config2.feedbackEndpoint)
15049
15179
  };
15050
15180
  this.buffer = {
15051
15181
  spans: [],
15182
+ logs: [],
15183
+ metrics: [],
15184
+ scores: [],
15185
+ feedback: [],
15052
15186
  totalSize: 0
15053
15187
  };
15054
15188
  }
@@ -15057,45 +15191,111 @@ var CloudExporter = class extends BaseExporter {
15057
15191
  return;
15058
15192
  }
15059
15193
  this.addToBuffer(event);
15060
- if (this.shouldFlush()) {
15061
- this.flush().catch((error48) => {
15062
- this.logger.error("Batch flush failed", {
15063
- error: error48 instanceof Error ? error48.message : String(error48)
15064
- });
15065
- });
15066
- } else if (this.buffer.totalSize === 1) {
15067
- this.scheduleFlush();
15194
+ await this.handleBufferedEvent();
15195
+ }
15196
+ async onLogEvent(event) {
15197
+ if (this.isDisabled) {
15198
+ return;
15068
15199
  }
15200
+ this.addLogToBuffer(event);
15201
+ await this.handleBufferedEvent();
15069
15202
  }
15070
- addToBuffer(event) {
15071
- if (this.buffer.totalSize === 0) {
15072
- this.buffer.firstEventTime = /* @__PURE__ */ new Date();
15203
+ async onMetricEvent(event) {
15204
+ if (this.isDisabled) {
15205
+ return;
15206
+ }
15207
+ this.addMetricToBuffer(event);
15208
+ await this.handleBufferedEvent();
15209
+ }
15210
+ async onScoreEvent(event) {
15211
+ if (this.isDisabled) {
15212
+ return;
15213
+ }
15214
+ this.addScoreToBuffer(event);
15215
+ await this.handleBufferedEvent();
15216
+ }
15217
+ async onFeedbackEvent(event) {
15218
+ if (this.isDisabled) {
15219
+ return;
15073
15220
  }
15221
+ this.addFeedbackToBuffer(event);
15222
+ await this.handleBufferedEvent();
15223
+ }
15224
+ addToBuffer(event) {
15225
+ this.markBufferStart();
15074
15226
  const spanRecord = this.formatSpan(event.exportedSpan);
15075
15227
  this.buffer.spans.push(spanRecord);
15076
15228
  this.buffer.totalSize++;
15077
15229
  }
15230
+ addLogToBuffer(event) {
15231
+ this.markBufferStart();
15232
+ this.buffer.logs.push(this.formatLog(event.log));
15233
+ this.buffer.totalSize++;
15234
+ }
15235
+ addMetricToBuffer(event) {
15236
+ this.markBufferStart();
15237
+ this.buffer.metrics.push(this.formatMetric(event.metric));
15238
+ this.buffer.totalSize++;
15239
+ }
15240
+ addScoreToBuffer(event) {
15241
+ this.markBufferStart();
15242
+ this.buffer.scores.push(this.formatScore(event.score));
15243
+ this.buffer.totalSize++;
15244
+ }
15245
+ addFeedbackToBuffer(event) {
15246
+ this.markBufferStart();
15247
+ this.buffer.feedback.push(this.formatFeedback(event.feedback));
15248
+ this.buffer.totalSize++;
15249
+ }
15250
+ markBufferStart() {
15251
+ if (this.buffer.totalSize === 0) {
15252
+ this.buffer.firstEventTime = /* @__PURE__ */ new Date();
15253
+ }
15254
+ }
15078
15255
  formatSpan(span) {
15079
15256
  const spanRecord = {
15080
- traceId: span.traceId,
15257
+ ...span,
15081
15258
  spanId: span.id,
15082
- parentSpanId: span.parentSpanId ?? null,
15083
- name: span.name,
15084
15259
  spanType: span.type,
15085
- attributes: span.attributes ?? null,
15086
- metadata: span.metadata ?? null,
15087
- requestContext: span.requestContext ?? null,
15088
15260
  startedAt: span.startTime,
15089
15261
  endedAt: span.endTime ?? null,
15090
- input: span.input ?? null,
15091
- output: span.output ?? null,
15092
- error: span.errorInfo,
15093
- isEvent: span.isEvent,
15262
+ error: span.errorInfo ?? null,
15094
15263
  createdAt: /* @__PURE__ */ new Date(),
15095
15264
  updatedAt: null
15096
15265
  };
15097
15266
  return spanRecord;
15098
15267
  }
15268
+ formatLog(log) {
15269
+ return {
15270
+ ...log
15271
+ };
15272
+ }
15273
+ formatMetric(metric) {
15274
+ return {
15275
+ ...metric
15276
+ };
15277
+ }
15278
+ formatScore(score) {
15279
+ return {
15280
+ ...score
15281
+ };
15282
+ }
15283
+ formatFeedback(feedback) {
15284
+ return {
15285
+ ...feedback
15286
+ };
15287
+ }
15288
+ async handleBufferedEvent() {
15289
+ if (this.shouldFlush()) {
15290
+ void this.flush().catch((error48) => {
15291
+ this.logger.error("Batch flush failed", {
15292
+ error: error48 instanceof Error ? error48.message : String(error48)
15293
+ });
15294
+ });
15295
+ } else if (this.buffer.totalSize === 1) {
15296
+ this.scheduleFlush();
15297
+ }
15298
+ }
15099
15299
  shouldFlush() {
15100
15300
  if (this.buffer.totalSize >= this.cloudConfig.maxBatchSize) {
15101
15301
  return true;
@@ -15113,7 +15313,7 @@ var CloudExporter = class extends BaseExporter {
15113
15313
  clearTimeout(this.flushTimer);
15114
15314
  }
15115
15315
  this.flushTimer = setTimeout(() => {
15116
- this.flush().catch((error48) => {
15316
+ void this.flush().catch((error48) => {
15117
15317
  const mastraError = new MastraError(
15118
15318
  {
15119
15319
  id: `CLOUD_EXPORTER_FAILED_TO_SCHEDULE_FLUSH`,
@@ -15137,49 +15337,91 @@ var CloudExporter = class extends BaseExporter {
15137
15337
  }
15138
15338
  const startTime = Date.now();
15139
15339
  const spansCopy = [...this.buffer.spans];
15340
+ const logsCopy = [...this.buffer.logs];
15341
+ const metricsCopy = [...this.buffer.metrics];
15342
+ const scoresCopy = [...this.buffer.scores];
15343
+ const feedbackCopy = [...this.buffer.feedback];
15344
+ const batchSize = this.buffer.totalSize;
15140
15345
  const flushReason = this.buffer.totalSize >= this.cloudConfig.maxBatchSize ? "size" : "time";
15141
15346
  this.resetBuffer();
15142
- try {
15143
- await this.batchUpload(spansCopy);
15144
- const elapsed = Date.now() - startTime;
15347
+ const results = await Promise.all([
15348
+ this.flushSignalBatch("traces", spansCopy),
15349
+ this.flushSignalBatch("logs", logsCopy),
15350
+ this.flushSignalBatch("metrics", metricsCopy),
15351
+ this.flushSignalBatch("scores", scoresCopy),
15352
+ this.flushSignalBatch("feedback", feedbackCopy)
15353
+ ]);
15354
+ const failedSignals = results.filter((result) => !result.succeeded).map((result) => result.signal);
15355
+ const elapsed = Date.now() - startTime;
15356
+ if (failedSignals.length === 0) {
15145
15357
  this.logger.debug("Batch flushed successfully", {
15146
- batchSize: spansCopy.length,
15358
+ batchSize,
15147
15359
  flushReason,
15148
15360
  durationMs: elapsed
15149
15361
  });
15362
+ return;
15363
+ }
15364
+ this.logger.warn("Batch flush completed with dropped signal batches", {
15365
+ batchSize,
15366
+ flushReason,
15367
+ durationMs: elapsed,
15368
+ failedSignals
15369
+ });
15370
+ }
15371
+ /**
15372
+ * Uploads a signal batch to the configured cloud API using fetchWithRetry.
15373
+ */
15374
+ async batchUpload(signal, records) {
15375
+ const headers = {
15376
+ Authorization: `Bearer ${this.cloudConfig.accessToken}`,
15377
+ "Content-Type": "application/json"
15378
+ };
15379
+ const endpointMap = {
15380
+ traces: this.cloudConfig.tracesEndpoint,
15381
+ logs: this.cloudConfig.logsEndpoint,
15382
+ metrics: this.cloudConfig.metricsEndpoint,
15383
+ scores: this.cloudConfig.scoresEndpoint,
15384
+ feedback: this.cloudConfig.feedbackEndpoint
15385
+ };
15386
+ const options = {
15387
+ method: "POST",
15388
+ headers,
15389
+ body: JSON.stringify({ [SIGNAL_PAYLOAD_KEYS[signal]]: records })
15390
+ };
15391
+ await fetchWithRetry(endpointMap[signal], options, this.cloudConfig.maxRetries);
15392
+ }
15393
+ async flushSignalBatch(signal, records) {
15394
+ if (records.length === 0) {
15395
+ return { signal, succeeded: true };
15396
+ }
15397
+ try {
15398
+ await this.batchUpload(signal, records);
15399
+ return { signal, succeeded: true };
15150
15400
  } catch (error48) {
15401
+ const errorId = `CLOUD_EXPORTER_FAILED_TO_BATCH_UPLOAD_${signal.toUpperCase()}`;
15151
15402
  const mastraError = new MastraError(
15152
15403
  {
15153
- id: `CLOUD_EXPORTER_FAILED_TO_BATCH_UPLOAD`,
15404
+ id: errorId,
15154
15405
  domain: ErrorDomain.MASTRA_OBSERVABILITY,
15155
15406
  category: ErrorCategory.USER,
15156
15407
  details: {
15157
- droppedBatchSize: spansCopy.length
15408
+ signal,
15409
+ droppedBatchSize: records.length
15158
15410
  }
15159
15411
  },
15160
15412
  error48
15161
15413
  );
15162
15414
  this.logger.trackException(mastraError);
15163
15415
  this.logger.error("Batch upload failed after all retries, dropping batch", mastraError);
15416
+ return { signal, succeeded: false };
15164
15417
  }
15165
15418
  }
15166
- /**
15167
- * Uploads spans to cloud API using fetchWithRetry for all retry logic
15168
- */
15169
- async batchUpload(spans) {
15170
- const headers = {
15171
- Authorization: `Bearer ${this.cloudConfig.accessToken}`,
15172
- "Content-Type": "application/json"
15173
- };
15174
- const options = {
15175
- method: "POST",
15176
- headers,
15177
- body: JSON.stringify({ spans })
15178
- };
15179
- await fetchWithRetry(this.cloudConfig.endpoint, options, this.cloudConfig.maxRetries);
15180
- }
15181
15419
  resetBuffer() {
15182
15420
  this.buffer.spans = [];
15421
+ this.buffer.logs = [];
15422
+ this.buffer.metrics = [];
15423
+ this.buffer.scores = [];
15424
+ this.buffer.feedback = [];
15183
15425
  this.buffer.firstEventTime = void 0;
15184
15426
  this.buffer.totalSize = 0;
15185
15427
  }
@@ -15192,11 +15434,21 @@ var CloudExporter = class extends BaseExporter {
15192
15434
  if (this.isDisabled) {
15193
15435
  return;
15194
15436
  }
15195
- if (this.buffer.totalSize > 0) {
15196
- this.logger.debug("Flushing buffered events", {
15197
- bufferedEvents: this.buffer.totalSize
15198
- });
15199
- await this.flushBuffer();
15437
+ while (this.buffer.totalSize > 0 || this.inFlightFlushes.size > 0) {
15438
+ if (this.buffer.totalSize > 0) {
15439
+ this.logger.debug("Flushing buffered events", {
15440
+ bufferedEvents: this.buffer.totalSize
15441
+ });
15442
+ const flushPromise = this.flushBuffer();
15443
+ this.inFlightFlushes.add(flushPromise);
15444
+ try {
15445
+ await flushPromise;
15446
+ } finally {
15447
+ this.inFlightFlushes.delete(flushPromise);
15448
+ }
15449
+ continue;
15450
+ }
15451
+ await Promise.allSettled([...this.inFlightFlushes]);
15200
15452
  }
15201
15453
  }
15202
15454
  async shutdown() {
@@ -17036,96 +17288,464 @@ var BaseObservabilityEventBus = class _BaseObservabilityEventBus extends MastraB
17036
17288
  }
17037
17289
  };
17038
17290
 
17039
- // src/bus/observability-bus.ts
17040
- var MAX_FLUSH_ITERATIONS = 3;
17041
- var ObservabilityBus = class extends BaseObservabilityEventBus {
17042
- exporters = [];
17043
- bridge;
17044
- /** In-flight handler promises from routeToHandler. Self-cleaning via .finally(). */
17045
- pendingHandlers = /* @__PURE__ */ new Set();
17046
- constructor() {
17047
- super({ name: "ObservabilityBus" });
17291
+ // src/spans/serialization.ts
17292
+ var DEFAULT_KEYS_TO_STRIP = /* @__PURE__ */ new Set([
17293
+ "logger",
17294
+ "experimental_providerMetadata",
17295
+ "providerMetadata",
17296
+ "steps",
17297
+ "tracingContext",
17298
+ "execute",
17299
+ // Tool execute functions
17300
+ "validate"
17301
+ // Schema validate functions
17302
+ ]);
17303
+ var DEFAULT_DEEP_CLEAN_OPTIONS = Object.freeze({
17304
+ keysToStrip: DEFAULT_KEYS_TO_STRIP,
17305
+ maxDepth: 8,
17306
+ maxStringLength: 128 * 1024,
17307
+ // 128KB - sufficient for large LLM prompts/responses
17308
+ maxArrayLength: 50,
17309
+ maxObjectKeys: 50
17310
+ });
17311
+ function mergeSerializationOptions(userOptions) {
17312
+ if (!userOptions) {
17313
+ return DEFAULT_DEEP_CLEAN_OPTIONS;
17048
17314
  }
17049
- /**
17050
- * Register an exporter to receive routed events.
17051
- * Duplicate registrations (same instance) are silently ignored.
17052
- *
17053
- * @param exporter - The exporter to register.
17054
- */
17055
- registerExporter(exporter) {
17056
- if (this.exporters.includes(exporter)) {
17057
- return;
17058
- }
17059
- this.exporters.push(exporter);
17315
+ return {
17316
+ keysToStrip: DEFAULT_KEYS_TO_STRIP,
17317
+ maxDepth: userOptions.maxDepth ?? DEFAULT_DEEP_CLEAN_OPTIONS.maxDepth,
17318
+ maxStringLength: userOptions.maxStringLength ?? DEFAULT_DEEP_CLEAN_OPTIONS.maxStringLength,
17319
+ maxArrayLength: userOptions.maxArrayLength ?? DEFAULT_DEEP_CLEAN_OPTIONS.maxArrayLength,
17320
+ maxObjectKeys: userOptions.maxObjectKeys ?? DEFAULT_DEEP_CLEAN_OPTIONS.maxObjectKeys
17321
+ };
17322
+ }
17323
+ function truncateString(s, maxChars) {
17324
+ if (s.length <= maxChars) {
17325
+ return s;
17060
17326
  }
17061
- /**
17062
- * Unregister an exporter.
17063
- *
17064
- * @param exporter - The exporter instance to remove.
17065
- * @returns `true` if the exporter was found and removed, `false` otherwise.
17066
- */
17067
- unregisterExporter(exporter) {
17068
- const index = this.exporters.indexOf(exporter);
17069
- if (index !== -1) {
17070
- this.exporters.splice(index, 1);
17071
- return true;
17072
- }
17073
- return false;
17327
+ return s.slice(0, maxChars) + "\u2026[truncated]";
17328
+ }
17329
+ function formatSerializationError(error48) {
17330
+ return `[${error48 instanceof Error ? truncateString(error48.message, 256) : "unknown error"}]`;
17331
+ }
17332
+ function getMapKeyType(key) {
17333
+ if (key === null) {
17334
+ return "null";
17074
17335
  }
17075
- /**
17076
- * Get registered exporters (read-only snapshot).
17077
- */
17078
- getExporters() {
17079
- return [...this.exporters];
17336
+ if (key instanceof Date) {
17337
+ return "date";
17080
17338
  }
17081
- /**
17082
- * Register a bridge to receive all routed events alongside exporters.
17083
- * Only one bridge can be registered at a time; replacing an existing bridge
17084
- * logs a warning.
17085
- *
17086
- * @param bridge - The bridge to register.
17087
- */
17088
- registerBridge(bridge) {
17089
- if (this.bridge) {
17090
- this.logger.warn(`[ObservabilityBus] Replacing existing bridge with new bridge`);
17091
- }
17092
- this.bridge = bridge;
17339
+ if (Array.isArray(key)) {
17340
+ return "array";
17093
17341
  }
17094
- /**
17095
- * Unregister the bridge.
17096
- *
17097
- * @returns `true` if a bridge was registered and removed, `false` otherwise.
17098
- */
17099
- unregisterBridge() {
17100
- if (this.bridge) {
17101
- this.bridge = void 0;
17102
- return true;
17103
- }
17104
- return false;
17342
+ if (key instanceof Map) {
17343
+ return "map";
17105
17344
  }
17106
- /**
17107
- * Get the registered bridge, if any.
17108
- */
17109
- getBridge() {
17110
- return this.bridge;
17345
+ if (key instanceof Set) {
17346
+ return "set";
17111
17347
  }
17112
- /**
17113
- * Emit an event: route to exporter/bridge handlers, then forward to base
17114
- * class for subscriber delivery.
17115
- *
17116
- * emit() is synchronous — async handler promises are tracked internally
17117
- * and can be drained via flush().
17118
- */
17119
- emit(event) {
17120
- for (const exporter of this.exporters) {
17121
- this.trackPromise(routeToHandler(exporter, event, this.logger));
17122
- }
17123
- if (this.bridge) {
17124
- this.trackPromise(routeToHandler(this.bridge, event, this.logger));
17125
- }
17126
- super.emit(event);
17348
+ if (key instanceof Error) {
17349
+ return "error";
17127
17350
  }
17128
- /**
17351
+ return typeof key;
17352
+ }
17353
+ function restoreSerializedMapKey(keyType, key) {
17354
+ switch (keyType) {
17355
+ case "undefined":
17356
+ return void 0;
17357
+ case "null":
17358
+ return null;
17359
+ case "bigint":
17360
+ return typeof key === "string" && key.endsWith("n") ? BigInt(key.slice(0, -1)) : key;
17361
+ case "date":
17362
+ return typeof key === "string" ? new Date(key) : key;
17363
+ default:
17364
+ return key;
17365
+ }
17366
+ }
17367
+ function isSerializedMap(value) {
17368
+ return typeof value === "object" && value !== null && value.__type === "Map" && Array.isArray(value.__map_entries);
17369
+ }
17370
+ function reconstructSerializedMap(value) {
17371
+ return new Map(
17372
+ value.__map_entries.map(([keyType, key, mapValue]) => [restoreSerializedMapKey(keyType, key), mapValue])
17373
+ );
17374
+ }
17375
+ function isJsonSchema(val) {
17376
+ if (typeof val !== "object" || val === null) return false;
17377
+ if (val.$schema && typeof val.$schema === "string" && val.$schema.includes("json-schema")) {
17378
+ return true;
17379
+ }
17380
+ if (val.type === "object" && val.properties && typeof val.properties === "object") {
17381
+ return true;
17382
+ }
17383
+ return false;
17384
+ }
17385
+ function compressJsonSchema(schema, depth = 0) {
17386
+ if (depth > 3) {
17387
+ return schema.type || "object";
17388
+ }
17389
+ const compositionKeys = ["oneOf", "anyOf", "allOf"].filter((key) => Array.isArray(schema[key]));
17390
+ if (compositionKeys.length > 0) {
17391
+ const compressed2 = {};
17392
+ for (const key of compositionKeys) {
17393
+ compressed2[key] = schema[key].map((entry) => compressJsonSchema(entry, depth + 1));
17394
+ }
17395
+ if (typeof schema.type === "string") {
17396
+ compressed2.type = schema.type;
17397
+ }
17398
+ return compressed2;
17399
+ }
17400
+ if (schema.type !== "object" || !schema.properties) {
17401
+ return schema.type || schema;
17402
+ }
17403
+ const required2 = new Set(Array.isArray(schema.required) ? schema.required : []);
17404
+ const compressed = {};
17405
+ for (const [key, propSchema] of Object.entries(schema.properties)) {
17406
+ const prop = propSchema;
17407
+ let value = prop.type || "unknown";
17408
+ if (prop.type === "object" && prop.properties) {
17409
+ value = compressJsonSchema(prop, depth + 1);
17410
+ if (required2.has(key)) {
17411
+ compressed[key + " (required)"] = value;
17412
+ continue;
17413
+ }
17414
+ } else if (prop.type === "array" && prop.items) {
17415
+ if (prop.items.type === "object" && prop.items.properties) {
17416
+ value = [compressJsonSchema(prop.items, depth + 1)];
17417
+ } else {
17418
+ value = `${prop.items.type || "any"}[]`;
17419
+ }
17420
+ } else if (prop.enum) {
17421
+ value = prop.enum.map((v) => JSON.stringify(v)).join(" | ");
17422
+ }
17423
+ if (required2.has(key) && typeof value === "string") {
17424
+ value += " (required)";
17425
+ }
17426
+ compressed[key] = value;
17427
+ }
17428
+ return compressed;
17429
+ }
17430
+ function deepClean(value, options = DEFAULT_DEEP_CLEAN_OPTIONS) {
17431
+ const { keysToStrip, maxDepth, maxStringLength, maxArrayLength, maxObjectKeys } = options;
17432
+ const stripSet = keysToStrip instanceof Set ? keysToStrip : new Set(Array.isArray(keysToStrip) ? keysToStrip : Object.keys(keysToStrip));
17433
+ const ancestors = /* @__PURE__ */ new WeakSet();
17434
+ function helper(val, depth) {
17435
+ if (depth > maxDepth) {
17436
+ return "[MaxDepth]";
17437
+ }
17438
+ if (val === null || val === void 0) {
17439
+ return val;
17440
+ }
17441
+ if (typeof val === "string") {
17442
+ return truncateString(val, maxStringLength);
17443
+ }
17444
+ if (typeof val === "number" || typeof val === "boolean") {
17445
+ return val;
17446
+ }
17447
+ if (typeof val === "bigint") {
17448
+ return `${val}n`;
17449
+ }
17450
+ if (typeof val === "function") {
17451
+ return "[Function]";
17452
+ }
17453
+ if (typeof val === "symbol") {
17454
+ return val.description ? `[Symbol(${val.description})]` : "[Symbol]";
17455
+ }
17456
+ if (val instanceof Date) {
17457
+ return val;
17458
+ }
17459
+ if (typeof val === "object") {
17460
+ if (ancestors.has(val)) {
17461
+ return "[Circular]";
17462
+ }
17463
+ ancestors.add(val);
17464
+ }
17465
+ try {
17466
+ if (val instanceof Error) {
17467
+ let errorName;
17468
+ let errorMessage;
17469
+ let errorStack;
17470
+ let rawCause;
17471
+ let causeReadFailed = false;
17472
+ try {
17473
+ errorName = val.name;
17474
+ } catch (error48) {
17475
+ errorName = formatSerializationError(error48);
17476
+ }
17477
+ try {
17478
+ errorMessage = val.message;
17479
+ } catch (error48) {
17480
+ errorMessage = formatSerializationError(error48);
17481
+ }
17482
+ try {
17483
+ errorStack = val.stack;
17484
+ } catch (error48) {
17485
+ errorStack = formatSerializationError(error48);
17486
+ }
17487
+ try {
17488
+ rawCause = val.cause;
17489
+ } catch (error48) {
17490
+ causeReadFailed = true;
17491
+ rawCause = formatSerializationError(error48);
17492
+ }
17493
+ const cleanedError = {
17494
+ name: typeof errorName === "string" ? truncateString(errorName, maxStringLength) : errorName,
17495
+ message: typeof errorMessage === "string" ? truncateString(errorMessage, maxStringLength) : errorMessage
17496
+ };
17497
+ if (typeof errorStack === "string") {
17498
+ cleanedError.stack = truncateString(errorStack, maxStringLength);
17499
+ } else if (errorStack !== void 0) {
17500
+ cleanedError.stack = errorStack;
17501
+ }
17502
+ if (causeReadFailed) {
17503
+ cleanedError.cause = rawCause;
17504
+ } else if (rawCause !== void 0) {
17505
+ try {
17506
+ cleanedError.cause = helper(rawCause, depth + 1);
17507
+ } catch (error48) {
17508
+ cleanedError.cause = formatSerializationError(error48);
17509
+ }
17510
+ }
17511
+ return cleanedError;
17512
+ }
17513
+ if (val instanceof Map) {
17514
+ const cleanedMap = { __type: "Map", __map_entries: [] };
17515
+ let mapKeyCount = 0;
17516
+ let omittedMapEntries = 0;
17517
+ for (const [mapKey, mapVal] of val) {
17518
+ if (typeof mapKey === "string" && stripSet.has(mapKey)) {
17519
+ continue;
17520
+ }
17521
+ if (mapKeyCount >= maxObjectKeys) {
17522
+ omittedMapEntries++;
17523
+ continue;
17524
+ }
17525
+ const mapKeyType = getMapKeyType(mapKey);
17526
+ let cleanedMapKey;
17527
+ let cleanedMapValue;
17528
+ try {
17529
+ cleanedMapKey = helper(mapKey, depth + 1);
17530
+ } catch (error48) {
17531
+ cleanedMapKey = formatSerializationError(error48);
17532
+ }
17533
+ try {
17534
+ cleanedMapValue = helper(mapVal, depth + 1);
17535
+ } catch (error48) {
17536
+ cleanedMapValue = formatSerializationError(error48);
17537
+ }
17538
+ cleanedMap.__map_entries.push([mapKeyType, cleanedMapKey, cleanedMapValue]);
17539
+ mapKeyCount++;
17540
+ }
17541
+ if (omittedMapEntries > 0) {
17542
+ cleanedMap.__truncated = `${omittedMapEntries} more keys omitted`;
17543
+ }
17544
+ return cleanedMap;
17545
+ }
17546
+ if (val instanceof Set) {
17547
+ const cleanedSet = [];
17548
+ let i = 0;
17549
+ const totalSetSize = val.size;
17550
+ for (const item of val) {
17551
+ if (i >= maxArrayLength) break;
17552
+ try {
17553
+ cleanedSet.push(helper(item, depth + 1));
17554
+ } catch (error48) {
17555
+ cleanedSet.push(formatSerializationError(error48));
17556
+ }
17557
+ i++;
17558
+ }
17559
+ if (totalSetSize > maxArrayLength) {
17560
+ cleanedSet.push(`[\u2026${totalSetSize - maxArrayLength} more items]`);
17561
+ }
17562
+ return cleanedSet;
17563
+ }
17564
+ if (Array.isArray(val)) {
17565
+ const cleaned2 = [];
17566
+ for (let i = 0; i < Math.min(val.length, maxArrayLength); i++) {
17567
+ try {
17568
+ cleaned2.push(helper(val[i], depth + 1));
17569
+ } catch (error48) {
17570
+ cleaned2.push(formatSerializationError(error48));
17571
+ }
17572
+ }
17573
+ if (val.length > maxArrayLength) {
17574
+ cleaned2.push(`[\u2026${val.length - maxArrayLength} more items]`);
17575
+ }
17576
+ return cleaned2;
17577
+ }
17578
+ if (typeof Buffer !== "undefined" && Buffer.isBuffer(val)) {
17579
+ return `[Buffer length=${val.length}]`;
17580
+ }
17581
+ if (ArrayBuffer.isView(val)) {
17582
+ const ctor = val.constructor?.name ?? "TypedArray";
17583
+ const byteLength = val.byteLength ?? "?";
17584
+ return `[${ctor} byteLength=${byteLength}]`;
17585
+ }
17586
+ if (val instanceof ArrayBuffer) {
17587
+ return `[ArrayBuffer byteLength=${val.byteLength}]`;
17588
+ }
17589
+ let serializeForSpan;
17590
+ try {
17591
+ serializeForSpan = val.serializeForSpan;
17592
+ } catch (error48) {
17593
+ return `[serializeForSpan failed: ${error48 instanceof Error ? truncateString(error48.message, 256) : "unknown error"}]`;
17594
+ }
17595
+ if (typeof serializeForSpan === "function") {
17596
+ try {
17597
+ return helper(serializeForSpan.call(val), depth);
17598
+ } catch (error48) {
17599
+ return `[serializeForSpan failed: ${error48 instanceof Error ? truncateString(error48.message, 256) : "unknown error"}]`;
17600
+ }
17601
+ }
17602
+ let looksLikeJsonSchema = false;
17603
+ try {
17604
+ looksLikeJsonSchema = isJsonSchema(val);
17605
+ } catch {
17606
+ looksLikeJsonSchema = false;
17607
+ }
17608
+ if (looksLikeJsonSchema) {
17609
+ try {
17610
+ const compressed = compressJsonSchema(val);
17611
+ return compressed === val ? "[JSONSchema]" : helper(compressed, depth);
17612
+ } catch {
17613
+ }
17614
+ }
17615
+ const cleaned = {};
17616
+ const keys = Object.keys(val).filter((key) => !stripSet.has(key));
17617
+ let keyCount = 0;
17618
+ for (const key of keys) {
17619
+ if (keyCount >= maxObjectKeys) {
17620
+ cleaned["__truncated"] = `${keys.length - keyCount} more keys omitted`;
17621
+ break;
17622
+ }
17623
+ try {
17624
+ cleaned[key] = helper(val[key], depth + 1);
17625
+ keyCount++;
17626
+ } catch (error48) {
17627
+ cleaned[key] = formatSerializationError(error48);
17628
+ keyCount++;
17629
+ }
17630
+ }
17631
+ return cleaned;
17632
+ } finally {
17633
+ if (typeof val === "object" && val !== null) {
17634
+ ancestors.delete(val);
17635
+ }
17636
+ }
17637
+ }
17638
+ return helper(value, 0);
17639
+ }
17640
+
17641
+ // src/bus/observability-bus.ts
17642
+ function cleanEvent(event, options) {
17643
+ switch (event.type) {
17644
+ case "log":
17645
+ return { type: "log", log: deepClean(event.log, options) };
17646
+ case "metric":
17647
+ return { type: "metric", metric: deepClean(event.metric, options) };
17648
+ case "score":
17649
+ return { type: "score", score: deepClean(event.score, options) };
17650
+ case "feedback":
17651
+ return { type: "feedback", feedback: deepClean(event.feedback, options) };
17652
+ default:
17653
+ return event;
17654
+ }
17655
+ }
17656
+ var MAX_FLUSH_ITERATIONS = 3;
17657
+ var ObservabilityBus = class extends BaseObservabilityEventBus {
17658
+ exporters = [];
17659
+ bridge;
17660
+ /** In-flight handler promises from routeToHandler. Self-cleaning via .finally(). */
17661
+ pendingHandlers = /* @__PURE__ */ new Set();
17662
+ /** Resolved deepClean options applied to non-tracing events before fan-out. */
17663
+ deepCleanOptions;
17664
+ constructor(opts) {
17665
+ super({ name: "ObservabilityBus" });
17666
+ this.deepCleanOptions = mergeSerializationOptions(opts?.serializationOptions);
17667
+ }
17668
+ /**
17669
+ * Register an exporter to receive routed events.
17670
+ * Duplicate registrations (same instance) are silently ignored.
17671
+ *
17672
+ * @param exporter - The exporter to register.
17673
+ */
17674
+ registerExporter(exporter) {
17675
+ if (this.exporters.includes(exporter)) {
17676
+ return;
17677
+ }
17678
+ this.exporters.push(exporter);
17679
+ }
17680
+ /**
17681
+ * Unregister an exporter.
17682
+ *
17683
+ * @param exporter - The exporter instance to remove.
17684
+ * @returns `true` if the exporter was found and removed, `false` otherwise.
17685
+ */
17686
+ unregisterExporter(exporter) {
17687
+ const index = this.exporters.indexOf(exporter);
17688
+ if (index !== -1) {
17689
+ this.exporters.splice(index, 1);
17690
+ return true;
17691
+ }
17692
+ return false;
17693
+ }
17694
+ /**
17695
+ * Get registered exporters (read-only snapshot).
17696
+ */
17697
+ getExporters() {
17698
+ return [...this.exporters];
17699
+ }
17700
+ /**
17701
+ * Register a bridge to receive all routed events alongside exporters.
17702
+ * Only one bridge can be registered at a time; replacing an existing bridge
17703
+ * logs a warning.
17704
+ *
17705
+ * @param bridge - The bridge to register.
17706
+ */
17707
+ registerBridge(bridge) {
17708
+ if (this.bridge) {
17709
+ this.logger.warn(`[ObservabilityBus] Replacing existing bridge with new bridge`);
17710
+ }
17711
+ this.bridge = bridge;
17712
+ }
17713
+ /**
17714
+ * Unregister the bridge.
17715
+ *
17716
+ * @returns `true` if a bridge was registered and removed, `false` otherwise.
17717
+ */
17718
+ unregisterBridge() {
17719
+ if (this.bridge) {
17720
+ this.bridge = void 0;
17721
+ return true;
17722
+ }
17723
+ return false;
17724
+ }
17725
+ /**
17726
+ * Get the registered bridge, if any.
17727
+ */
17728
+ getBridge() {
17729
+ return this.bridge;
17730
+ }
17731
+ /**
17732
+ * Emit an event: route to exporter/bridge handlers, then forward to base
17733
+ * class for subscriber delivery.
17734
+ *
17735
+ * emit() is synchronous — async handler promises are tracked internally
17736
+ * and can be drained via flush().
17737
+ */
17738
+ emit(event) {
17739
+ const cleaned = cleanEvent(event, this.deepCleanOptions);
17740
+ for (const exporter of this.exporters) {
17741
+ this.trackPromise(routeToHandler(exporter, cleaned, this.logger));
17742
+ }
17743
+ if (this.bridge) {
17744
+ this.trackPromise(routeToHandler(this.bridge, cleaned, this.logger));
17745
+ }
17746
+ super.emit(cleaned);
17747
+ }
17748
+ /**
17129
17749
  * Track an async handler promise so flush() can await it.
17130
17750
  * No-ops for sync (void) results.
17131
17751
  */
@@ -18394,218 +19014,6 @@ var ModelSpanTracker = class {
18394
19014
  }
18395
19015
  };
18396
19016
 
18397
- // src/spans/serialization.ts
18398
- var DEFAULT_KEYS_TO_STRIP = /* @__PURE__ */ new Set([
18399
- "logger",
18400
- "experimental_providerMetadata",
18401
- "providerMetadata",
18402
- "steps",
18403
- "tracingContext",
18404
- "execute",
18405
- // Tool execute functions
18406
- "validate"
18407
- // Schema validate functions
18408
- ]);
18409
- var DEFAULT_DEEP_CLEAN_OPTIONS = Object.freeze({
18410
- keysToStrip: DEFAULT_KEYS_TO_STRIP,
18411
- maxDepth: 8,
18412
- maxStringLength: 128 * 1024,
18413
- // 128KB - sufficient for large LLM prompts/responses
18414
- maxArrayLength: 50,
18415
- maxObjectKeys: 50
18416
- });
18417
- function mergeSerializationOptions(userOptions) {
18418
- if (!userOptions) {
18419
- return DEFAULT_DEEP_CLEAN_OPTIONS;
18420
- }
18421
- return {
18422
- keysToStrip: DEFAULT_KEYS_TO_STRIP,
18423
- maxDepth: userOptions.maxDepth ?? DEFAULT_DEEP_CLEAN_OPTIONS.maxDepth,
18424
- maxStringLength: userOptions.maxStringLength ?? DEFAULT_DEEP_CLEAN_OPTIONS.maxStringLength,
18425
- maxArrayLength: userOptions.maxArrayLength ?? DEFAULT_DEEP_CLEAN_OPTIONS.maxArrayLength,
18426
- maxObjectKeys: userOptions.maxObjectKeys ?? DEFAULT_DEEP_CLEAN_OPTIONS.maxObjectKeys
18427
- };
18428
- }
18429
- function truncateString(s, maxChars) {
18430
- if (s.length <= maxChars) {
18431
- return s;
18432
- }
18433
- return s.slice(0, maxChars) + "\u2026[truncated]";
18434
- }
18435
- function isJsonSchema(val) {
18436
- if (typeof val !== "object" || val === null) return false;
18437
- if (val.$schema && typeof val.$schema === "string" && val.$schema.includes("json-schema")) {
18438
- return true;
18439
- }
18440
- if (val.type === "object" && val.properties && typeof val.properties === "object") {
18441
- return true;
18442
- }
18443
- return false;
18444
- }
18445
- function compressJsonSchema(schema, depth = 0) {
18446
- if (depth > 3) {
18447
- return schema.type || "object";
18448
- }
18449
- const compositionKeys = ["oneOf", "anyOf", "allOf"].filter((key) => Array.isArray(schema[key]));
18450
- if (compositionKeys.length > 0) {
18451
- const compressed2 = {};
18452
- for (const key of compositionKeys) {
18453
- compressed2[key] = schema[key].map((entry) => compressJsonSchema(entry, depth + 1));
18454
- }
18455
- if (typeof schema.type === "string") {
18456
- compressed2.type = schema.type;
18457
- }
18458
- return compressed2;
18459
- }
18460
- if (schema.type !== "object" || !schema.properties) {
18461
- return schema.type || schema;
18462
- }
18463
- const required2 = new Set(Array.isArray(schema.required) ? schema.required : []);
18464
- const compressed = {};
18465
- for (const [key, propSchema] of Object.entries(schema.properties)) {
18466
- const prop = propSchema;
18467
- let value = prop.type || "unknown";
18468
- if (prop.type === "object" && prop.properties) {
18469
- value = compressJsonSchema(prop, depth + 1);
18470
- if (required2.has(key)) {
18471
- compressed[key + " (required)"] = value;
18472
- continue;
18473
- }
18474
- } else if (prop.type === "array" && prop.items) {
18475
- if (prop.items.type === "object" && prop.items.properties) {
18476
- value = [compressJsonSchema(prop.items, depth + 1)];
18477
- } else {
18478
- value = `${prop.items.type || "any"}[]`;
18479
- }
18480
- } else if (prop.enum) {
18481
- value = prop.enum.map((v) => JSON.stringify(v)).join(" | ");
18482
- }
18483
- if (required2.has(key) && typeof value === "string") {
18484
- value += " (required)";
18485
- }
18486
- compressed[key] = value;
18487
- }
18488
- return compressed;
18489
- }
18490
- function deepClean(value, options = DEFAULT_DEEP_CLEAN_OPTIONS) {
18491
- const { keysToStrip, maxDepth, maxStringLength, maxArrayLength, maxObjectKeys } = options;
18492
- const stripSet = keysToStrip instanceof Set ? keysToStrip : new Set(Array.isArray(keysToStrip) ? keysToStrip : Object.keys(keysToStrip));
18493
- const ancestors = /* @__PURE__ */ new WeakSet();
18494
- function helper(val, depth) {
18495
- if (depth > maxDepth) {
18496
- return "[MaxDepth]";
18497
- }
18498
- if (val === null || val === void 0) {
18499
- return val;
18500
- }
18501
- if (typeof val === "string") {
18502
- return truncateString(val, maxStringLength);
18503
- }
18504
- if (typeof val === "number" || typeof val === "boolean") {
18505
- return val;
18506
- }
18507
- if (typeof val === "bigint") {
18508
- return `${val}n`;
18509
- }
18510
- if (typeof val === "function") {
18511
- return "[Function]";
18512
- }
18513
- if (typeof val === "symbol") {
18514
- return val.description ? `[Symbol(${val.description})]` : "[Symbol]";
18515
- }
18516
- if (val instanceof Date) {
18517
- return val;
18518
- }
18519
- if (val instanceof Error) {
18520
- return {
18521
- name: val.name,
18522
- message: val.message ? truncateString(val.message, maxStringLength) : void 0
18523
- };
18524
- }
18525
- if (typeof val === "object") {
18526
- if (ancestors.has(val)) {
18527
- return "[Circular]";
18528
- }
18529
- ancestors.add(val);
18530
- }
18531
- try {
18532
- if (Array.isArray(val)) {
18533
- const cleaned2 = [];
18534
- for (let i = 0; i < Math.min(val.length, maxArrayLength); i++) {
18535
- try {
18536
- cleaned2.push(helper(val[i], depth + 1));
18537
- } catch (error48) {
18538
- cleaned2.push(`[${error48 instanceof Error ? truncateString(error48.message, 256) : "unknown error"}]`);
18539
- }
18540
- }
18541
- if (val.length > maxArrayLength) {
18542
- cleaned2.push(`[\u2026${val.length - maxArrayLength} more items]`);
18543
- }
18544
- return cleaned2;
18545
- }
18546
- if (typeof Buffer !== "undefined" && Buffer.isBuffer(val)) {
18547
- return `[Buffer length=${val.length}]`;
18548
- }
18549
- if (ArrayBuffer.isView(val)) {
18550
- const ctor = val.constructor?.name ?? "TypedArray";
18551
- const byteLength = val.byteLength ?? "?";
18552
- return `[${ctor} byteLength=${byteLength}]`;
18553
- }
18554
- if (val instanceof ArrayBuffer) {
18555
- return `[ArrayBuffer byteLength=${val.byteLength}]`;
18556
- }
18557
- let serializeForSpan;
18558
- try {
18559
- serializeForSpan = val.serializeForSpan;
18560
- } catch (error48) {
18561
- return `[serializeForSpan failed: ${error48 instanceof Error ? truncateString(error48.message, 256) : "unknown error"}]`;
18562
- }
18563
- if (typeof serializeForSpan === "function") {
18564
- try {
18565
- return helper(serializeForSpan.call(val), depth);
18566
- } catch (error48) {
18567
- return `[serializeForSpan failed: ${error48 instanceof Error ? truncateString(error48.message, 256) : "unknown error"}]`;
18568
- }
18569
- }
18570
- let looksLikeJsonSchema = false;
18571
- try {
18572
- looksLikeJsonSchema = isJsonSchema(val);
18573
- } catch {
18574
- looksLikeJsonSchema = false;
18575
- }
18576
- if (looksLikeJsonSchema) {
18577
- try {
18578
- const compressed = compressJsonSchema(val);
18579
- return compressed === val ? "[JSONSchema]" : helper(compressed, depth);
18580
- } catch {
18581
- }
18582
- }
18583
- const cleaned = {};
18584
- const keys = Object.keys(val).filter((key) => !stripSet.has(key));
18585
- let keyCount = 0;
18586
- for (const key of keys) {
18587
- if (keyCount >= maxObjectKeys) {
18588
- cleaned["__truncated"] = `${keys.length - keyCount} more keys omitted`;
18589
- break;
18590
- }
18591
- try {
18592
- cleaned[key] = helper(val[key], depth + 1);
18593
- keyCount++;
18594
- } catch (error48) {
18595
- cleaned[key] = `[${error48 instanceof Error ? truncateString(error48.message, 256) : "unknown error"}]`;
18596
- keyCount++;
18597
- }
18598
- }
18599
- return cleaned;
18600
- } finally {
18601
- if (typeof val === "object" && val !== null) {
18602
- ancestors.delete(val);
18603
- }
18604
- }
18605
- }
18606
- return helper(value, 0);
18607
- }
18608
-
18609
19017
  // src/spans/base.ts
18610
19018
  function isSpanInternal(spanType, flags) {
18611
19019
  if (flags === void 0 || flags === InternalSpans.NONE) {
@@ -19064,7 +19472,9 @@ var BaseObservabilityInstance = class extends MastraBase {
19064
19472
  logging: config2.logging
19065
19473
  };
19066
19474
  this.cardinalityFilter = new CardinalityFilter(config2.cardinality);
19067
- this.observabilityBus = new ObservabilityBus();
19475
+ this.observabilityBus = new ObservabilityBus({
19476
+ serializationOptions: this.config.serializationOptions
19477
+ });
19068
19478
  for (const exporter of this.exporters) {
19069
19479
  this.observabilityBus.registerExporter(exporter);
19070
19480
  }
@@ -20397,6 +20807,6 @@ function buildTracingOptions(...updaters) {
20397
20807
  return updaters.reduce((opts, updater) => updater(opts), {});
20398
20808
  }
20399
20809
 
20400
- 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, mergeSerializationOptions, observabilityConfigValueSchema, observabilityInstanceConfigSchema, observabilityRegistryConfigSchema, routeToHandler, samplingStrategySchema, serializationOptionsSchema, truncateString };
20810
+ 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 };
20401
20811
  //# sourceMappingURL=index.js.map
20402
20812
  //# sourceMappingURL=index.js.map