UNPKG

@mastra/core

Version:
1,005 lines 70.2 kB
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