@mastra/core
Version:
1,005 lines • 70.2 kB
JavaScript
require("./tracing-BUrUJwCM.cjs");
let zod_v4 = require("zod/v4");
//#region ../_internal-core/dist/storage/index.js
/** Types of entities that can produce observability spans. */
let EntityType = /* @__PURE__ */ function(EntityType) {
/** Agent/Model execution */
EntityType["AGENT"] = "agent";
/** Scorer definition/execution */
EntityType["SCORER"] = "scorer";
/** RAG ingestion pipeline execution */
EntityType["RAG_INGESTION"] = "rag_ingestion";
/** Trajectory evaluation target */
EntityType["TRAJECTORY"] = "trajectory";
/** Input Processor */
EntityType["INPUT_PROCESSOR"] = "input_processor";
/** Input Step Processor */
EntityType["INPUT_STEP_PROCESSOR"] = "input_step_processor";
/** Output Processor */
EntityType["OUTPUT_PROCESSOR"] = "output_processor";
/** Output Step Processor */
EntityType["OUTPUT_STEP_PROCESSOR"] = "output_step_processor";
/** Tool Result Processor */
EntityType["TOOL_RESULT_PROCESSOR"] = "tool_result_processor";
/** Workflow Step */
EntityType["WORKFLOW_STEP"] = "workflow_step";
/** Tool */
EntityType["TOOL"] = "tool";
/** Workflow */
EntityType["WORKFLOW_RUN"] = "workflow_run";
/** Memory */
EntityType["MEMORY"] = "memory";
return EntityType;
}({});
/**
* Common DB fields
*/
const createdAtField = zod_v4.z.date().describe("Database record creation time");
const updatedAtField = zod_v4.z.date().describe("Database record last update time");
const dbTimestamps = {
createdAt: createdAtField,
updatedAt: updatedAtField.nullable()
};
/**
* Pagination arguments for list queries (page and perPage only)
* Uses z.coerce to handle string → number conversion from query params
*/
const paginationArgsSchema = zod_v4.z.object({
page: zod_v4.z.coerce.number().int().min(0).optional().default(0).describe("Zero-indexed page number"),
perPage: zod_v4.z.coerce.number().int().min(1).max(100).optional().default(10).describe("Number of items per page")
}).describe("Pagination options for list queries");
/**
* Pagination response info
* Used across all paginated endpoints
*/
const paginationInfoSchema = zod_v4.z.object({
total: zod_v4.z.number().describe("Total number of items available"),
page: zod_v4.z.number().describe("Current page"),
perPage: zod_v4.z.union([zod_v4.z.number(), zod_v4.z.literal(false)]).describe("Number of items per page, or false if pagination is disabled"),
hasMore: zod_v4.z.boolean().describe("True if more pages are available")
});
/** Opaque cursor used to resume incremental polling for observability list endpoints. */
const deltaCursorSchema = zod_v4.z.string().min(1).describe("Opaque cursor value for incremental polling");
/** Explicit list mode selector for observability list endpoints. */
const listModeSchema = zod_v4.z.enum(["page", "delta"]).describe("List mode: 'page' | 'delta', defaults to 'page' when omitted.");
/** Max number of updates returned from a delta poll window. */
const deltaLimitSchema = zod_v4.z.coerce.number().int().min(1).max(100).optional().describe("Maximum number of updates to return in one delta poll");
/** Default page-mode pagination used to preserve legacy list arg behavior. */
const defaultPaginationArgs = {
page: 0,
perPage: 10
};
/** Default number of updates returned when delta mode does not specify a limit. */
const defaultDeltaLimit = 10;
/**
* Enforces the shared page-vs-delta parameter rules for observability list endpoints.
* Keeps validation centralized while allowing endpoints to keep their own filters and orderBy schemas.
*/
function refineObservabilityListMode(value, ctx) {
if (value.mode === "delta") {
if (value.pagination !== void 0) ctx.addIssue({
code: "custom",
path: ["pagination"],
message: "pagination is not allowed in delta mode"
});
if (value.orderBy !== void 0) ctx.addIssue({
code: "custom",
path: ["orderBy"],
message: "orderBy is not allowed in delta mode"
});
return;
}
if (value.after !== void 0) ctx.addIssue({
code: "custom",
path: ["after"],
message: "after is only allowed in delta mode"
});
if (value.limit !== void 0) ctx.addIssue({
code: "custom",
path: ["limit"],
message: "limit is only allowed in delta mode"
});
}
/**
* Normalizes observability list args into the legacy-friendly shape expected by existing stores.
* Page mode remains the default, and pagination/orderBy/limit are always populated.
*/
function normalizeObservabilityListArgs(value, defaults) {
return {
mode: value.mode === "delta" ? "delta" : "page",
filters: value.filters,
pagination: value.pagination ?? defaults.pagination ?? defaultPaginationArgs,
orderBy: value.orderBy ?? defaults.orderBy,
after: value.after,
limit: value.limit ?? defaults.limit ?? 10
};
}
/** Metadata returned for a delta poll window. */
const deltaInfoSchema = zod_v4.z.object({
limit: zod_v4.z.number().describe("Maximum number of updates requested for this delta poll"),
hasMore: zod_v4.z.boolean().describe("True when more matching updates remain after this response")
}).describe("Incremental polling metadata");
/**
* Date range for filtering by time
* Uses z.coerce to handle ISO string → Date conversion from query params
*/
const dateRangeSchema = zod_v4.z.object({
start: zod_v4.z.coerce.date().optional().describe("Start of date range (inclusive by default)"),
end: zod_v4.z.coerce.date().optional().describe("End of date range (inclusive by default)"),
startExclusive: zod_v4.z.boolean().optional().describe("When true, excludes the start date from results (uses > instead of >=)"),
endExclusive: zod_v4.z.boolean().optional().describe("When true, excludes the end date from results (uses < instead of <=)")
}).describe("Date range filter for timestamps");
const sortDirectionSchema = zod_v4.z.enum(["ASC", "DESC"]).describe("Sort direction: 'ASC' | 'DESC'");
/** Aggregation type schema shared across OLAP-style observability queries. */
const aggregationTypeSchema = zod_v4.z.enum([
"sum",
"avg",
"min",
"max",
"count",
"count_distinct",
"last"
]).describe("Aggregation function");
/** Aggregation interval schema shared across OLAP-style observability queries. */
const aggregationIntervalSchema = zod_v4.z.enum([
"1m",
"5m",
"15m",
"1h",
"1d"
]).describe("Time bucket interval");
/** Compare period for aggregate queries with period-over-period comparison. */
const comparePeriodSchema = zod_v4.z.enum([
"previous_period",
"previous_day",
"previous_week"
]).describe("Comparison period for aggregate queries");
/** Shared groupBy schema for OLAP-style breakdown and time-series queries. */
const groupBySchema = zod_v4.z.array(zod_v4.z.string()).min(1).describe("Fields to group by");
/** Shared percentiles schema for percentile queries. */
const percentilesSchema = zod_v4.z.array(zod_v4.z.number().min(0).max(1)).min(1).describe("Percentile values (0-1)");
/** Shared fields for aggregate OLAP responses across observability signals. */
const aggregateResponseFields = {
value: zod_v4.z.number().nullable().describe("Aggregated value"),
previousValue: zod_v4.z.number().nullable().optional().describe("Value from comparison period"),
changePercent: zod_v4.z.number().nullable().optional().describe("Percentage change from comparison period")
};
/** Shared field for OLAP breakdown dimension values. */
const dimensionsField = zod_v4.z.record(zod_v4.z.string(), zod_v4.z.string().nullable()).describe("Dimension values for this group");
/** Shared field for non-null OLAP aggregated values. */
const aggregatedValueField = zod_v4.z.number().describe("Aggregated value");
/** Shared field for OLAP bucket timestamps. */
const bucketTimestampField = zod_v4.z.date().describe("Bucket timestamp");
/** Shared field for percentile identifiers in OLAP responses. */
const percentileField = zod_v4.z.number().describe("Percentile value");
/** Shared field for percentile values within a time bucket. */
const percentileBucketValueField = zod_v4.z.number().describe("Percentile value at this bucket");
const entityTypeField = zod_v4.z.nativeEnum(EntityType).describe(`Entity type (e.g., 'agent' | 'processor' | 'tool' | 'workflow')`);
const entityIdField = zod_v4.z.string().describe("ID of the entity (e.g., \"weatherAgent\", \"orderWorkflow\")");
const entityNameField = zod_v4.z.string().describe("Name of the entity");
const userIdField = zod_v4.z.string().describe("Human end-user who triggered execution");
const organizationIdField = zod_v4.z.string().describe("Multi-tenant organization/account");
const resourceIdField = zod_v4.z.string().describe("Broader resource context (Mastra memory compatibility)");
const runIdField = zod_v4.z.string().describe("Unique execution run identifier");
const sessionIdField = zod_v4.z.string().describe("Session identifier for grouping traces");
const threadIdField = zod_v4.z.string().describe("Conversation thread identifier");
const requestIdField = zod_v4.z.string().describe("HTTP request ID for log correlation");
const environmentField = zod_v4.z.string().describe(`Environment (e.g., "production" | "staging" | "development")`);
const sourceField = zod_v4.z.string().describe(`Source of execution (e.g., "local" | "cloud" | "ci")`);
const executionSourceField = zod_v4.z.string().describe(`Source of execution (e.g., "local" | "cloud" | "ci")`);
const serviceNameField = zod_v4.z.string().describe("Name of the service");
const parentEntityTypeField = zod_v4.z.nativeEnum(EntityType).describe("Entity type of the parent entity");
const parentEntityIdField = zod_v4.z.string().describe("ID of the parent entity");
const parentEntityNameField = zod_v4.z.string().describe("Name of the parent entity");
const rootEntityTypeField = zod_v4.z.nativeEnum(EntityType).describe("Entity type of the root entity");
const rootEntityIdField = zod_v4.z.string().describe("ID of the root entity");
const rootEntityNameField = zod_v4.z.string().describe("Name of the root entity");
const entityVersionIdField = zod_v4.z.string().describe("Version ID of the entity that produced this signal (e.g., agent version, workflow version)");
const parentEntityVersionIdField = zod_v4.z.string().describe("Version ID of the parent entity that produced this signal");
const rootEntityVersionIdField = zod_v4.z.string().describe("Version ID of the root entity that produced this signal");
const experimentIdField = zod_v4.z.string().describe("Experiment or eval run identifier");
const scopeField = zod_v4.z.record(zod_v4.z.string(), zod_v4.z.unknown()).describe("Arbitrary package/app version info (e.g., {\"core\": \"1.0.0\", \"memory\": \"1.0.0\", \"gitSha\": \"abcd1234\"})");
const metadataField = zod_v4.z.record(zod_v4.z.string(), zod_v4.z.unknown()).describe("User-defined metadata for custom filtering");
const tagsField = zod_v4.z.array(zod_v4.z.string()).describe("Labels for filtering");
/**
* Base context fields shared across tracing and non-tracing observability records.
* Source/provenance is intentionally excluded because tracing uses `source`
* while signals use `executionSource`.
*/
const contextFieldsBase = {
entityType: entityTypeField.nullish(),
entityId: entityIdField.nullish(),
entityName: entityNameField.nullish(),
parentEntityType: parentEntityTypeField.nullish(),
parentEntityId: parentEntityIdField.nullish(),
parentEntityName: parentEntityNameField.nullish(),
rootEntityType: rootEntityTypeField.nullish(),
rootEntityId: rootEntityIdField.nullish(),
rootEntityName: rootEntityNameField.nullish(),
userId: userIdField.nullish(),
organizationId: organizationIdField.nullish(),
resourceId: resourceIdField.nullish(),
runId: runIdField.nullish(),
sessionId: sessionIdField.nullish(),
threadId: threadIdField.nullish(),
requestId: requestIdField.nullish(),
environment: environmentField.nullish(),
serviceName: serviceNameField.nullish(),
scope: scopeField.nullish(),
entityVersionId: entityVersionIdField.nullish(),
parentEntityVersionId: parentEntityVersionIdField.nullish(),
rootEntityVersionId: rootEntityVersionIdField.nullish(),
experimentId: experimentIdField.nullish()
};
/**
* Context fields shared across observability signals other than spans (metrics, logs, scores, feedback).
* These use `executionSource` to avoid colliding with signal-specific provenance fields.
*/
const contextFields = {
...contextFieldsBase,
executionSource: executionSourceField.nullish(),
tags: tagsField.nullish()
};
/**
* Context fields used by tracing/span records.
* Tracing continues to expose execution provenance as `source`.
*/
const spanContextFields = {
...contextFieldsBase,
source: sourceField.nullish()
};
/**
* Common filter fields shared across observability signal filters (metrics, logs, scores, feedback).
* All fields are optional — each signal extends this with signal-specific filters.
*/
const commonFilterFields = {
timestamp: dateRangeSchema.optional().describe("Filter by timestamp range"),
traceId: zod_v4.z.string().optional().describe("Filter by trace ID"),
spanId: zod_v4.z.string().optional().describe("Filter by span ID"),
entityType: entityTypeField.optional(),
entityName: entityNameField.optional(),
entityVersionId: entityVersionIdField.optional(),
parentEntityVersionId: parentEntityVersionIdField.optional(),
rootEntityVersionId: rootEntityVersionIdField.optional(),
userId: userIdField.optional(),
organizationId: organizationIdField.optional(),
experimentId: experimentIdField.optional(),
serviceName: serviceNameField.optional(),
environment: environmentField.optional(),
parentEntityType: parentEntityTypeField.optional(),
parentEntityName: parentEntityNameField.optional(),
rootEntityType: rootEntityTypeField.optional(),
rootEntityName: rootEntityNameField.optional(),
resourceId: resourceIdField.optional(),
runId: runIdField.optional(),
sessionId: sessionIdField.optional(),
threadId: threadIdField.optional(),
requestId: requestIdField.optional(),
executionSource: executionSourceField.optional(),
tags: zod_v4.z.array(zod_v4.z.string()).optional().describe("Filter by tags (must have all specified tags)")
};
/** Zod schema for trace ID field */
const traceIdField = zod_v4.z.string().describe("Unique trace identifier");
/** Zod schema for span ID field */
const spanIdField = zod_v4.z.string().describe("Unique span identifier within a trace");
/** Log level schema for validation */
const logLevelSchema = zod_v4.z.enum([
"debug",
"info",
"warn",
"error",
"fatal"
]);
const messageField = zod_v4.z.string().describe("Log message");
const logDataField = zod_v4.z.record(zod_v4.z.string(), zod_v4.z.unknown()).describe("Structured data attached to the log");
/**
* Schema for logs as stored in the database.
* Includes all fields from ExportedLog plus storage-specific fields.
*/
const logRecordSchema = zod_v4.z.object({
logId: zod_v4.z.string().nullish().describe("Unique id for this log event"),
timestamp: zod_v4.z.date().describe("When the log was created"),
level: logLevelSchema.describe("Log severity level"),
message: messageField,
data: logDataField.nullish(),
traceId: traceIdField.nullish(),
spanId: spanIdField.nullish(),
...contextFields,
/**
* @deprecated Use `executionSource` instead.
*/
source: zod_v4.z.string().nullish().describe("Execution source"),
metadata: metadataField.nullish()
}).describe("Log record as stored in the database");
/**
* Schema for user-provided log input (minimal required fields).
* The logger enriches this with context before emitting ExportedLog.
*/
const logRecordInputSchema = zod_v4.z.object({
level: logLevelSchema,
message: messageField,
data: logDataField.optional(),
tags: tagsField.optional()
}).describe("User-provided log input");
/** Schema for creating a log record */
const createLogRecordSchema = logRecordSchema;
/** Schema for batchCreateLogs operation arguments */
const batchCreateLogsArgsSchema = zod_v4.z.object({ logs: zod_v4.z.array(createLogRecordSchema) }).describe("Arguments for batch creating logs");
/** Schema for filtering logs in list queries */
const logsFilterSchema = zod_v4.z.object({
...commonFilterFields,
/**
* @deprecated Use `executionSource` instead.
*/
source: zod_v4.z.string().optional().describe("Filter by execution source"),
level: zod_v4.z.union([logLevelSchema, zod_v4.z.array(logLevelSchema)]).optional().describe("Filter by log level(s)")
}).describe("Filters for querying logs");
/** Fields available for ordering log results */
const logsOrderByFieldSchema = zod_v4.z.enum(["timestamp"]).describe("Field to order by: 'timestamp'");
/** Order by configuration for log queries */
const logsOrderBySchema = zod_v4.z.object({
field: logsOrderByFieldSchema.default("timestamp").describe("Field to order by"),
direction: sortDirectionSchema.default("DESC").describe("Sort direction")
}).describe("Order by configuration");
/** Schema for listLogs operation arguments */
const listLogsArgsSchema = zod_v4.z.object({
mode: listModeSchema.optional(),
filters: logsFilterSchema.optional().describe("Optional filters to apply"),
pagination: paginationArgsSchema.optional(),
orderBy: logsOrderBySchema.optional(),
after: deltaCursorSchema.optional(),
limit: deltaLimitSchema
}).strict().superRefine(refineObservabilityListMode).transform((value) => normalizeObservabilityListArgs(value, { orderBy: {
field: "timestamp",
direction: "DESC"
} })).describe("Arguments for listing logs");
/** Schema for listLogs operation response */
const listLogsResponseSchema = zod_v4.z.object({
pagination: paginationInfoSchema.optional(),
delta: deltaInfoSchema.optional(),
deltaCursor: deltaCursorSchema.optional(),
logs: zod_v4.z.array(logRecordSchema)
}).describe("Response from listing logs");
const scorerIdField = zod_v4.z.string().describe("Identifier of the scorer (e.g., relevance, accuracy)");
const scorerNameField = zod_v4.z.string().describe("Display name of the scorer");
const scorerVersionField = zod_v4.z.string().describe("Version of the scorer");
const scoreSourceField = zod_v4.z.string().describe("How the score was produced (e.g., manual, automated, experiment)");
const scoreValueField = zod_v4.z.number().describe("Score value (range defined by scorer)");
const scoreReasonField = zod_v4.z.string().describe("Explanation for the score");
/**
* Schema for scores as stored in the database.
* Includes all fields from ExportedScore plus storage-specific fields.
*/
const scoreRecordSchema = zod_v4.z.object({
scoreId: zod_v4.z.string().nullish().describe("Unique id for this score event"),
timestamp: zod_v4.z.date().describe("When the score was recorded"),
traceId: traceIdField.nullish().describe("Trace that anchors the scored target when available"),
spanId: spanIdField.nullish().describe("Span ID this score applies to"),
scorerId: scorerIdField,
scorerName: scorerNameField.nullish(),
scorerVersion: scorerVersionField.nullish(),
scoreSource: scoreSourceField.nullish(),
/**
* @deprecated Use `scoreSource` instead.
*/
source: scoreSourceField.nullish(),
score: scoreValueField,
reason: scoreReasonField.nullish(),
...contextFields,
/** Trace ID of the scoring run (links to trace that generated this score) */
scoreTraceId: zod_v4.z.string().nullish().describe("Trace ID of the scoring run for debugging score generation"),
metadata: zod_v4.z.record(zod_v4.z.string(), zod_v4.z.unknown()).nullish().describe("User-defined metadata")
}).describe("Score record as stored in the database");
/**
* Schema for user-provided score input (minimal required fields).
* The span/trace context adds traceId/spanId before emitting ExportedScore.
*/
const scoreInputSchema = zod_v4.z.object({
scorerId: scorerIdField,
scorerName: scorerNameField.optional(),
scorerVersion: scorerVersionField.optional(),
scoreSource: scoreSourceField.optional(),
/**
* @deprecated Use `scoreSource` instead.
*/
source: scoreSourceField.optional(),
score: scoreValueField,
reason: scoreReasonField.optional(),
metadata: zod_v4.z.record(zod_v4.z.string(), zod_v4.z.unknown()).optional().describe("Additional scorer-specific metadata"),
experimentId: experimentIdField.optional(),
scoreTraceId: zod_v4.z.string().optional().describe("Trace ID of the scoring run for debugging score generation"),
targetEntityType: entityTypeField.optional().describe("Entity type the scorer evaluated when known")
}).describe("User-provided score input");
/** Schema for creating a score record */
const createScoreRecordSchema = scoreRecordSchema;
/** Schema for createScore operation arguments */
const createScoreArgsSchema = zod_v4.z.object({ score: createScoreRecordSchema }).describe("Arguments for creating a score");
/** Schema for createScore operation body in client/server */
const createScoreBodySchema = zod_v4.z.object({ score: createScoreRecordSchema.omit({ timestamp: true }) }).describe("Arguments for creating a score");
/** Schema for createScore operation response */
const createScoreResponseSchema = zod_v4.z.object({ success: zod_v4.z.boolean() }).describe("Response from creating a score");
/** Schema for batchCreateScores operation arguments */
const batchCreateScoresArgsSchema = zod_v4.z.object({ scores: zod_v4.z.array(createScoreRecordSchema) }).describe("Arguments for batch recording scores");
/** Schema for filtering scores in list queries */
const scoresFilterSchema = zod_v4.z.object({
...commonFilterFields,
scorerId: zod_v4.z.union([zod_v4.z.string(), zod_v4.z.array(zod_v4.z.string())]).optional().describe("Filter by scorer ID(s)"),
scoreSource: scoreSourceField.optional().describe("Filter by how the score was produced"),
/**
* @deprecated Use `scoreSource` instead.
*/
source: scoreSourceField.optional().describe("Filter by how the score was produced")
}).describe("Filters for querying scores");
/** Fields available for ordering score results */
const scoresOrderByFieldSchema = zod_v4.z.enum(["timestamp", "score"]).describe("Field to order by: 'timestamp' | 'score'");
/** Order by configuration for score queries */
const scoresOrderBySchema = zod_v4.z.object({
field: scoresOrderByFieldSchema.default("timestamp").describe("Field to order by"),
direction: sortDirectionSchema.default("DESC").describe("Sort direction")
}).describe("Order by configuration");
const listScoresArgsSchema = zod_v4.z.object({
mode: listModeSchema.optional(),
filters: scoresFilterSchema.optional(),
pagination: paginationArgsSchema.optional(),
orderBy: scoresOrderBySchema.optional(),
after: deltaCursorSchema.optional(),
limit: deltaLimitSchema
}).strict().superRefine(refineObservabilityListMode).transform((value) => normalizeObservabilityListArgs(value, { orderBy: {
field: "timestamp",
direction: "DESC"
} })).describe("Arguments for listing scores");
/** Schema for listScores operation response */
const listScoresResponseSchema = zod_v4.z.object({
pagination: paginationInfoSchema.optional(),
delta: deltaInfoSchema.optional(),
deltaCursor: deltaCursorSchema.optional(),
scores: zod_v4.z.array(scoreRecordSchema)
}).describe("Response from listing scores");
const getScoreAggregateArgsSchema = zod_v4.z.object({
scorerId: scorerIdField,
scoreSource: scoreSourceField.optional(),
aggregation: aggregationTypeSchema,
filters: scoresFilterSchema.optional(),
comparePeriod: comparePeriodSchema.optional()
}).describe("Arguments for getting a score aggregate");
const getScoreAggregateResponseSchema = zod_v4.z.object(aggregateResponseFields);
const getScoreBreakdownArgsSchema = zod_v4.z.object({
scorerId: scorerIdField,
scoreSource: scoreSourceField.optional(),
groupBy: groupBySchema,
aggregation: aggregationTypeSchema,
filters: scoresFilterSchema.optional()
}).describe("Arguments for getting a score breakdown");
const getScoreBreakdownResponseSchema = zod_v4.z.object({ groups: zod_v4.z.array(zod_v4.z.object({
dimensions: dimensionsField,
value: aggregatedValueField
})) });
const getScoreTimeSeriesArgsSchema = zod_v4.z.object({
scorerId: scorerIdField,
scoreSource: scoreSourceField.optional(),
interval: aggregationIntervalSchema,
aggregation: aggregationTypeSchema,
filters: scoresFilterSchema.optional(),
groupBy: groupBySchema.optional()
}).describe("Arguments for getting score time series");
const getScoreTimeSeriesResponseSchema = zod_v4.z.object({ series: zod_v4.z.array(zod_v4.z.object({
name: zod_v4.z.string().describe("Series name (scorer ID or group key)"),
points: zod_v4.z.array(zod_v4.z.object({
timestamp: bucketTimestampField,
value: aggregatedValueField
}))
})) });
const getScorePercentilesArgsSchema = zod_v4.z.object({
scorerId: scorerIdField,
scoreSource: scoreSourceField.optional(),
percentiles: percentilesSchema,
interval: aggregationIntervalSchema,
filters: scoresFilterSchema.optional()
}).describe("Arguments for getting score percentiles");
const getScorePercentilesResponseSchema = zod_v4.z.object({ series: zod_v4.z.array(zod_v4.z.object({
percentile: percentileField,
points: zod_v4.z.array(zod_v4.z.object({
timestamp: bucketTimestampField,
value: percentileBucketValueField
}))
})) });
const feedbackSourceField = zod_v4.z.string().describe("Source of feedback (e.g., 'user', 'system', 'manual')");
const feedbackTypeField = zod_v4.z.string().describe("Type of feedback (e.g., 'thumbs', 'rating', 'correction')");
const feedbackValueField = zod_v4.z.union([zod_v4.z.number(), zod_v4.z.string()]).describe("Feedback value (rating number or correction text)");
const feedbackCommentField = zod_v4.z.string().describe("Additional comment or context");
const feedbackUserIdField = zod_v4.z.string().describe("User who provided the feedback");
function normalizeLegacyFeedbackActor(input) {
if (!input || typeof input !== "object" || Array.isArray(input)) return input;
const record = { ...input };
if (typeof record.userId === "string" && record.feedbackUserId == null) {
record.feedbackUserId = record.userId;
delete record.userId;
}
return record;
}
/**
* Schema for feedback as stored in the database.
* Includes all fields from ExportedFeedback plus storage-specific fields.
*/
const feedbackRecordObjectSchema = zod_v4.z.object({
feedbackId: zod_v4.z.string().nullish().describe("Unique id for this feedback event"),
timestamp: zod_v4.z.date().describe("When the feedback was recorded"),
traceId: traceIdField.nullish().describe("Trace that anchors the feedback target when available"),
spanId: spanIdField.nullish().describe("Span ID this feedback applies to"),
feedbackSource: feedbackSourceField.nullish(),
/**
* @deprecated Use `feedbackSource` instead.
*/
source: feedbackSourceField.nullish(),
feedbackType: feedbackTypeField,
value: feedbackValueField,
comment: feedbackCommentField.nullish(),
feedbackUserId: feedbackUserIdField.nullish(),
...contextFields,
sourceId: zod_v4.z.string().nullish().describe("ID of the source record this feedback is linked to (e.g. experiment result ID)"),
metadata: zod_v4.z.record(zod_v4.z.string(), zod_v4.z.unknown()).nullish().describe("User-defined metadata")
});
const feedbackRecordSchema = zod_v4.z.object(feedbackRecordObjectSchema.shape).describe("Feedback record as stored in the database");
/**
* Schema for user-provided feedback input (minimal required fields).
* The span/trace context adds traceId/spanId before emitting ExportedFeedback.
*/
const feedbackInputObjectSchema = zod_v4.z.object({
feedbackSource: feedbackSourceField.optional(),
/**
* @deprecated Use `feedbackSource` instead.
*/
source: feedbackSourceField.optional(),
feedbackType: feedbackTypeField,
value: feedbackValueField,
comment: feedbackCommentField.optional(),
feedbackUserId: feedbackUserIdField.optional(),
/**
* @deprecated Use `feedbackUserId` instead.
*/
userId: feedbackUserIdField.optional(),
metadata: zod_v4.z.record(zod_v4.z.string(), zod_v4.z.unknown()).optional().describe("Additional feedback-specific metadata"),
experimentId: experimentIdField.optional(),
sourceId: zod_v4.z.string().optional().describe("ID of the source record this feedback is linked to")
});
const feedbackInputSchema = zod_v4.z.object(feedbackInputObjectSchema.shape).describe("User-provided feedback input");
/** Schema for creating a feedback record */
const createFeedbackRecordSchema = feedbackRecordSchema;
/** Schema for createFeedback operation arguments */
const createFeedbackArgsSchema = zod_v4.z.object({ feedback: zod_v4.z.preprocess(normalizeLegacyFeedbackActor, feedbackRecordObjectSchema) }).describe("Arguments for creating feedback");
/** Schema for createFeedback operation body in client/server */
const createFeedbackBodySchema = zod_v4.z.object({ feedback: feedbackRecordObjectSchema.omit({ timestamp: true }) }).describe("Arguments for creating feedback");
/** Schema for createFeedback operation response */
const createFeedbackResponseSchema = zod_v4.z.object({ success: zod_v4.z.boolean() }).describe("Response from creating feedback");
/** Schema for batchCreateFeedback operation arguments */
const batchCreateFeedbackArgsSchema = zod_v4.z.object({ feedbacks: zod_v4.z.array(zod_v4.z.preprocess(normalizeLegacyFeedbackActor, feedbackRecordObjectSchema)) }).describe("Arguments for batch recording feedback");
/** Schema for filtering feedback in list queries */
const feedbackFilterObjectSchema = zod_v4.z.object({
...commonFilterFields,
feedbackType: zod_v4.z.union([zod_v4.z.string(), zod_v4.z.array(zod_v4.z.string())]).optional().describe("Filter by feedback type(s)"),
feedbackSource: feedbackSourceField.optional(),
/**
* @deprecated Use `feedbackSource` instead.
*/
source: feedbackSourceField.optional(),
feedbackUserId: feedbackUserIdField.optional()
});
const feedbackFilterSchema = zod_v4.z.object(feedbackFilterObjectSchema.shape).describe("Filters for querying feedback");
/** Fields available for ordering feedback results */
const feedbackOrderByFieldSchema = zod_v4.z.enum(["timestamp"]).describe("Field to order by: 'timestamp'");
/** Order by configuration for feedback queries */
const feedbackOrderBySchema = zod_v4.z.object({
field: feedbackOrderByFieldSchema.default("timestamp").describe("Field to order by"),
direction: sortDirectionSchema.default("DESC").describe("Sort direction")
}).describe("Order by configuration");
const listFeedbackArgsSchema = zod_v4.z.object({
mode: listModeSchema.optional(),
filters: zod_v4.z.preprocess(normalizeLegacyFeedbackActor, feedbackFilterObjectSchema).optional(),
pagination: paginationArgsSchema.optional(),
orderBy: feedbackOrderBySchema.optional(),
after: deltaCursorSchema.optional(),
limit: deltaLimitSchema
}).strict().superRefine(refineObservabilityListMode).transform((value) => normalizeObservabilityListArgs(value, { orderBy: {
field: "timestamp",
direction: "DESC"
} })).describe("Arguments for listing feedback");
/** Schema for listFeedback operation response */
const listFeedbackResponseSchema = zod_v4.z.object({
pagination: paginationInfoSchema.optional(),
delta: deltaInfoSchema.optional(),
deltaCursor: deltaCursorSchema.optional(),
feedback: zod_v4.z.array(feedbackRecordSchema)
}).describe("Response from listing feedback");
const getFeedbackAggregateArgsSchema = zod_v4.z.object({
feedbackType: feedbackTypeField,
feedbackSource: feedbackSourceField.optional(),
aggregation: aggregationTypeSchema,
filters: feedbackFilterSchema.optional(),
comparePeriod: comparePeriodSchema.optional()
}).describe("Arguments for getting a feedback aggregate over numeric values");
const getFeedbackAggregateResponseSchema = zod_v4.z.object(aggregateResponseFields);
const getFeedbackBreakdownArgsSchema = zod_v4.z.object({
feedbackType: feedbackTypeField,
feedbackSource: feedbackSourceField.optional(),
groupBy: groupBySchema,
aggregation: aggregationTypeSchema,
filters: feedbackFilterSchema.optional()
}).describe("Arguments for getting a feedback breakdown over numeric values");
const getFeedbackBreakdownResponseSchema = zod_v4.z.object({ groups: zod_v4.z.array(zod_v4.z.object({
dimensions: dimensionsField,
value: aggregatedValueField
})) });
const getFeedbackTimeSeriesArgsSchema = zod_v4.z.object({
feedbackType: feedbackTypeField,
feedbackSource: feedbackSourceField.optional(),
interval: aggregationIntervalSchema,
aggregation: aggregationTypeSchema,
filters: feedbackFilterSchema.optional(),
groupBy: groupBySchema.optional()
}).describe("Arguments for getting feedback time series over numeric values");
const getFeedbackTimeSeriesResponseSchema = zod_v4.z.object({ series: zod_v4.z.array(zod_v4.z.object({
name: zod_v4.z.string().describe("Series name (feedback type or group key)"),
points: zod_v4.z.array(zod_v4.z.object({
timestamp: bucketTimestampField,
value: aggregatedValueField
}))
})) });
const getFeedbackPercentilesArgsSchema = zod_v4.z.object({
feedbackType: feedbackTypeField,
feedbackSource: feedbackSourceField.optional(),
percentiles: percentilesSchema,
interval: aggregationIntervalSchema,
filters: feedbackFilterSchema.optional()
}).describe("Arguments for getting feedback percentiles over numeric values");
const getFeedbackPercentilesResponseSchema = zod_v4.z.object({ series: zod_v4.z.array(zod_v4.z.object({
percentile: percentileField,
points: zod_v4.z.array(zod_v4.z.object({
timestamp: bucketTimestampField,
value: percentileBucketValueField
}))
})) });
/**
* @deprecated MetricType is no longer stored. All metrics are raw events
* with aggregation determined at query time.
*/
const metricTypeSchema = zod_v4.z.enum([
"counter",
"gauge",
"histogram"
]);
const metricNameField = zod_v4.z.string().describe("Metric name (e.g., mastra_agent_duration_ms)");
const metricValueField = zod_v4.z.number().describe("Metric value");
const labelsField = zod_v4.z.record(zod_v4.z.string(), zod_v4.z.string()).describe("Metric labels for dimensional filtering");
const providerField = zod_v4.z.string().describe("Model provider");
const modelField = zod_v4.z.string().describe("Model");
const estimatedCostField = zod_v4.z.number().describe("Estimated cost");
const costUnitField = zod_v4.z.string().describe("Unit for the estimated cost (e.g., usd)");
const costMetadField = zod_v4.z.record(zod_v4.z.string(), zod_v4.z.unknown()).nullish().describe("Structured costing metadata");
/**
* Schema for metrics as stored in the database.
* Each record is a single metric observation.
*/
const metricRecordSchema = zod_v4.z.object({
metricId: zod_v4.z.string().nullish().describe("Unique id for this metric event"),
timestamp: zod_v4.z.date().describe("When the metric was recorded"),
name: metricNameField,
value: metricValueField,
traceId: traceIdField.nullish(),
spanId: spanIdField.nullish(),
...contextFields,
/**
* @deprecated Use `executionSource` instead.
*/
source: zod_v4.z.string().nullish().describe("Execution source"),
provider: providerField.nullish(),
model: modelField.nullish(),
estimatedCost: estimatedCostField.nullish(),
costUnit: costUnitField.nullish(),
costMetadata: costMetadField.nullish(),
labels: labelsField.default({}),
metadata: metadataField.nullish()
}).describe("Metric record as stored in the database");
/**
* Schema for user-provided metric input (minimal required fields).
* The metrics context enriches this with environment before emitting ExportedMetric.
*/
const metricInputSchema = zod_v4.z.object({
name: metricNameField,
value: metricValueField,
labels: labelsField.optional()
}).describe("User-provided metric input");
/** Schema for creating a metric record (without db timestamps) */
const createMetricRecordSchema = metricRecordSchema;
/** Schema for batchCreateMetrics operation arguments */
const batchCreateMetricsArgsSchema = zod_v4.z.object({ metrics: zod_v4.z.array(createMetricRecordSchema) }).describe("Arguments for batch recording metrics");
/** Schema for metric aggregation configuration */
const metricsAggregationSchema = zod_v4.z.object({
type: aggregationTypeSchema,
interval: aggregationIntervalSchema.optional(),
groupBy: groupBySchema.optional()
}).describe("Metrics aggregation configuration");
/** Schema for filtering metrics in queries */
const metricsFilterSchema = zod_v4.z.object({
...commonFilterFields,
traceIds: zod_v4.z.array(traceIdField).nonempty().max(1e3).optional().describe("Filter by one or more trace IDs"),
name: zod_v4.z.array(zod_v4.z.string()).nonempty().optional().describe("Filter by metric name(s)"),
/**
* @deprecated Use `executionSource` instead.
*/
source: zod_v4.z.string().optional().describe("Filter by execution source"),
provider: providerField.optional(),
model: modelField.optional(),
costUnit: costUnitField.optional(),
labels: zod_v4.z.record(zod_v4.z.string(), zod_v4.z.string()).optional().describe("Exact match on label key-value pairs")
}).describe("Filters for querying metrics");
/** Fields available for ordering metric list results */
const metricsOrderByFieldSchema = zod_v4.z.enum(["timestamp"]).describe("Field to order by: 'timestamp'");
/** Order by configuration for metric list queries */
const metricsOrderBySchema = zod_v4.z.object({
field: metricsOrderByFieldSchema.default("timestamp").describe("Field to order by"),
direction: sortDirectionSchema.default("DESC").describe("Sort direction")
}).describe("Order by configuration");
const listMetricsArgsSchema = zod_v4.z.object({
mode: listModeSchema.optional(),
filters: metricsFilterSchema.optional(),
pagination: paginationArgsSchema.optional(),
orderBy: metricsOrderBySchema.optional(),
after: deltaCursorSchema.optional(),
limit: deltaLimitSchema
}).strict().superRefine(refineObservabilityListMode).transform((value) => normalizeObservabilityListArgs(value, { orderBy: {
field: "timestamp",
direction: "DESC"
} })).describe("Arguments for listing metrics");
/** Schema for listMetrics operation response */
const listMetricsResponseSchema = zod_v4.z.object({
pagination: paginationInfoSchema.optional(),
delta: deltaInfoSchema.optional(),
deltaCursor: deltaCursorSchema.optional(),
metrics: zod_v4.z.array(metricRecordSchema)
}).describe("Response from listing metrics");
/**
* Columns eligible for `count_distinct`.
*
* Restricted to low/medium-cardinality categorical attributes. ID columns are
* intentionally excluded — approximate distinct count over near-unique values
* converges to the row count and is rarely a useful KPI.
*/
const METRIC_DISTINCT_COLUMNS = [
"entityType",
"entityName",
"parentEntityType",
"parentEntityName",
"rootEntityType",
"rootEntityName",
"name",
"provider",
"model",
"environment",
"executionSource",
"serviceName",
"threadId",
"resourceId"
];
const distinctColumnSchema = zod_v4.z.enum(METRIC_DISTINCT_COLUMNS).optional().describe("Column to apply count_distinct over (required when aggregation is 'count_distinct'). Restricted to allowlisted metric dimensions.");
const requireDistinctColumnRefinement = {
check: (data) => data.aggregation !== "count_distinct" || data.distinctColumn !== void 0,
options: {
message: "distinctColumn is required when aggregation is 'count_distinct'",
path: ["distinctColumn"]
}
};
const getMetricAggregateArgsSchema = zod_v4.z.object({
name: zod_v4.z.array(zod_v4.z.string()).nonempty().describe("Metric name(s) to aggregate"),
aggregation: aggregationTypeSchema,
distinctColumn: distinctColumnSchema,
filters: metricsFilterSchema.optional(),
comparePeriod: comparePeriodSchema.optional()
}).refine(requireDistinctColumnRefinement.check, requireDistinctColumnRefinement.options).describe("Arguments for getting a metric aggregate");
const getMetricAggregateResponseSchema = zod_v4.z.object({
...aggregateResponseFields,
estimatedCost: zod_v4.z.number().nullable().optional().describe("Aggregated estimated cost from the same filtered row set"),
costUnit: zod_v4.z.string().nullable().optional().describe("Shared cost unit for the aggregated rows, or null when mixed/unknown"),
previousEstimatedCost: zod_v4.z.number().nullable().optional().describe("Aggregated estimated cost from the comparison period"),
costChangePercent: zod_v4.z.number().nullable().optional().describe("Percentage change in estimated cost from comparison period")
});
const getMetricBreakdownArgsSchema = zod_v4.z.object({
name: zod_v4.z.array(zod_v4.z.string()).nonempty().describe("Metric name(s) to break down"),
groupBy: groupBySchema,
aggregation: aggregationTypeSchema,
distinctColumn: distinctColumnSchema,
filters: metricsFilterSchema.optional(),
limit: zod_v4.z.number().int().positive().max(1e3).optional().describe("Maximum number of groups to return (server-side TopK). Required for high-cardinality groupBy."),
orderDirection: sortDirectionSchema.optional().describe("Sort direction for the aggregated value (defaults to 'DESC' at the storage layer; pairs with limit for top/bottom-N).")
}).refine(requireDistinctColumnRefinement.check, requireDistinctColumnRefinement.options).describe("Arguments for getting a metric breakdown");
const getMetricBreakdownResponseSchema = zod_v4.z.object({ groups: zod_v4.z.array(zod_v4.z.object({
dimensions: dimensionsField,
value: aggregatedValueField,
estimatedCost: zod_v4.z.number().nullable().optional().describe("Summed estimated cost for this group"),
costUnit: zod_v4.z.string().nullable().optional().describe("Shared cost unit for this group, or null when mixed/unknown")
})) });
const getMetricTimeSeriesArgsSchema = zod_v4.z.object({
name: zod_v4.z.array(zod_v4.z.string()).nonempty().describe("Metric name(s)"),
interval: aggregationIntervalSchema,
aggregation: aggregationTypeSchema,
distinctColumn: distinctColumnSchema,
filters: metricsFilterSchema.optional(),
groupBy: groupBySchema.optional()
}).refine(requireDistinctColumnRefinement.check, requireDistinctColumnRefinement.options).describe("Arguments for getting metric time series");
const getMetricTimeSeriesResponseSchema = zod_v4.z.object({ series: zod_v4.z.array(zod_v4.z.object({
name: zod_v4.z.string().describe("Series name (metric name or group key)"),
costUnit: zod_v4.z.string().nullable().optional().describe("Shared cost unit for this series, or null when mixed/unknown"),
points: zod_v4.z.array(zod_v4.z.object({
timestamp: bucketTimestampField,
value: aggregatedValueField,
estimatedCost: zod_v4.z.number().nullable().optional().describe("Summed estimated cost in this bucket")
}))
})) });
const getMetricPercentilesArgsSchema = zod_v4.z.object({
name: zod_v4.z.string().describe("Metric name"),
percentiles: percentilesSchema,
interval: aggregationIntervalSchema,
filters: metricsFilterSchema.optional()
}).describe("Arguments for getting metric percentiles");
const getMetricPercentilesResponseSchema = zod_v4.z.object({ series: zod_v4.z.array(zod_v4.z.object({
percentile: percentileField,
points: zod_v4.z.array(zod_v4.z.object({
timestamp: bucketTimestampField,
value: percentileBucketValueField
}))
})) });
const getMetricNamesArgsSchema = zod_v4.z.object({
prefix: zod_v4.z.string().optional().describe("Filter metric names by prefix"),
limit: zod_v4.z.coerce.number().int().min(1).optional().describe("Maximum number of names to return")
}).describe("Arguments for getting metric names");
const getMetricNamesResponseSchema = zod_v4.z.object({ names: zod_v4.z.array(zod_v4.z.string()).describe("Distinct metric names") });
const getMetricLabelKeysArgsSchema = zod_v4.z.object({ metricName: zod_v4.z.string().describe("Metric name to get label keys for") }).describe("Arguments for getting metric label keys");
const getMetricLabelKeysResponseSchema = zod_v4.z.object({ keys: zod_v4.z.array(zod_v4.z.string()).describe("Distinct label keys for the metric") });
const getMetricLabelValuesArgsSchema = zod_v4.z.object({
metricName: zod_v4.z.string().describe("Metric name"),
labelKey: zod_v4.z.string().describe("Label key to get values for"),
prefix: zod_v4.z.string().optional().describe("Filter values by prefix"),
limit: zod_v4.z.coerce.number().int().min(1).optional().describe("Maximum number of values to return")
}).describe("Arguments for getting label values");
const getMetricLabelValuesResponseSchema = zod_v4.z.object({ values: zod_v4.z.array(zod_v4.z.string()).describe("Distinct label values") });
const getEntityTypesArgsSchema = zod_v4.z.object({}).describe("Arguments for getting entity types");
const getEntityTypesResponseSchema = zod_v4.z.object({ entityTypes: zod_v4.z.array(entityTypeField).describe("Distinct entity types") });
const getEntityNamesArgsSchema = zod_v4.z.object({ entityType: entityTypeField.optional().describe("Optional entity type filter") }).describe("Arguments for getting entity names");
const getEntityNamesResponseSchema = zod_v4.z.object({ names: zod_v4.z.array(zod_v4.z.string()).describe("Distinct entity names") });
const getServiceNamesArgsSchema = zod_v4.z.object({}).describe("Arguments for getting service names");
const getServiceNamesResponseSchema = zod_v4.z.object({ serviceNames: zod_v4.z.array(zod_v4.z.string()).describe("Distinct service names") });
const getEnvironmentsArgsSchema = zod_v4.z.object({}).describe("Arguments for getting environments");
const getEnvironmentsResponseSchema = zod_v4.z.object({ environments: zod_v4.z.array(zod_v4.z.string()).describe("Distinct environments") });
const getTagsArgsSchema = zod_v4.z.object({ entityType: entityTypeField.optional().describe("Optional entity type filter") }).describe("Arguments for getting tags");
const getTagsResponseSchema = zod_v4.z.object({ tags: zod_v4.z.array(zod_v4.z.string()).describe("Distinct tags") });
//#endregion
//#region src/observability/utils.ts
/**
* Browser-safe observability utilities.
*
* Functions that depend on AsyncLocalStorage (getCurrentSpan, executeWithContext,
* executeWithContextSync) are in context-storage.ts and should only be imported
* by server-side code.
*/
const entityTypeValues = new Set(Object.values(EntityType));
let currentSpanResolver;
function setCurrentSpanResolver(resolver) {
currentSpanResolver = resolver;
}
function resolveCurrentSpan() {
return currentSpanResolver?.();
}
/** Generate a unique id for an observability signal (log, metric, score, feedback). */
function generateSignalId() {
return crypto.randomUUID();
}
/**
* Compute the names of tools the model can call on a single inference step,
* applying `activeTools` filtering when present. Used to populate the
* `availableTools` attribute on MODEL_INFERENCE spans so observers see the
* post-processor tool set, which can differ per-step from the AGENT_RUN view.
*
* `activeTools` is treated by presence, not truthiness: an explicit empty
* array means "no tools enabled for this step" and is honored as such.
* Returns `[]` (not `undefined`) when `tools` is provided but empty, so a
* tool-less agent still reports a definitive empty list to observers.
*/
function getStepAvailableToolNames(tools, activeTools) {
if (activeTools !== void 0) return [...activeTools];
if (tools) return Object.keys(tools);
}
let executeWithContextImpl;
let executeWithContextSyncImpl;
function setExecuteWithContext(impl) {
executeWithContextImpl = impl;
}
function setExecuteWithContextSync(impl) {
executeWithContextSyncImpl = impl;
}
/**
* Execute an async function within a span's tracing context.
* Falls back to direct execution if no context-storage implementation is registered or no span exists.
*/
async function executeWithContext(params) {
if (executeWithContextImpl) return executeWithContextImpl(params);
const { span, fn } = params;
if (span?.executeInContext) return span.executeInContext(fn);
return fn();
}
/**
* Execute a sync function within a span's tracing context.
* Falls back to direct execution if no context-storage implementation is registered or no span exists.
*/
function executeWithContextSync(params) {
if (executeWithContextSyncImpl) return executeWithContextSyncImpl(params);
const { span, fn } = params;
if (span?.executeInContextSync) return span.executeInContextSync(fn);
return fn();
}
/**
* Creates or gets a child span from existing tracing context or starts a new trace.
* This helper consolidates the common pattern of creating spans that can either be:
* 1. Children of an existing span (when tracingContext.currentSpan exists)
* 2. New root spans (when no current span exists)
*
* @param options - Configuration object for span creation
* @returns The created Span or undefined if tracing is disabled
*/
function getOrCreateSpan(options) {
const { type, attributes, tracingContext, requestContext, tracingOptions, ...rest } = options;
const metadata = {
...rest.metadata ?? {},
...tracingOptions?.metadata ?? {}
};
if (tracingContext?.currentSpan) return tracingContext.currentSpan.createChildSpan({
type,
attributes,
...rest,
metadata,
requestContext
});
return (options.mastra?.observability?.getSelectedInstance({ requestContext }))?.startSpan({
type,
attributes,
...rest,
metadata,
requestContext,
tracingOptions,
traceId: tracingOptions?.traceId,
parentSpanId: tracingOptions?.parentSpanId,
customSamplerOptions: {
requestContext,
metadata
}
});
}
/**
* Returns the top-most non-internal span that would appear in exported tracing output.
*
* Public API results should use this span for trace/span correlation because internal Mastra
* workflow spans are omitted from external exporters.
*/
function getRootExportSpan(span) {
if (!span?.isValid) return;
let current = span;
let rootExportSpan = span.isInternal ? void 0 : span;
while (current?.parent) {
current = current.parent;
if (!current.isInternal) rootExportSpan = current;
}
return rootExportSpan;
}
/**
* Resolves the best available entity type for a span-like record.
*
* Prefers an explicit `entityType` when present and valid, then falls back to the
* span type for common observability entities.
*/
function getEntityTypeForSpan(span) {
if (span.entityType && entityTypeValues.has(span.entityType)) return span.entityType;
switch (span.spanType) {
case "agent_run": return EntityType.AGENT;
case "rag_ingestion": return EntityType.RAG_INGESTION;
case "scorer_run":
case "scorer_step": return EntityType.SCORER;
case "workflow_run": return EntityType.WORKFLOW_RUN;
case "workflow_step": return EntityType.WO