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