UNPKG

@mastra/core

Version:
1,014 lines 52.3 kB
import "./tracing-Bm0k4FBA.js"; import { z } from "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 = z.date().describe("Database record creation time"); const updatedAtField = 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 = z.object({ page: z.coerce.number().int().min(0).optional().default(0).describe("Zero-indexed page number"), perPage: 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 = z.object({ total: z.number().describe("Total number of items available"), page: z.number().describe("Current page"), perPage: z.union([z.number(), z.literal(false)]).describe("Number of items per page, or false if pagination is disabled"), hasMore: z.boolean().describe("True if more pages are available") }); /** Opaque cursor used to resume incremental polling for observability list endpoints. */ const deltaCursorSchema = z.string().min(1).describe("Opaque cursor value for incremental polling"); /** Explicit list mode selector for observability list endpoints. */ const listModeSchema = 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 = 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 = z.object({ limit: z.number().describe("Maximum number of updates requested for this delta poll"), hasMore: 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 = z.object({ start: z.coerce.date().optional().describe("Start of date range (inclusive by default)"), end: z.coerce.date().optional().describe("End of date range (inclusive by default)"), startExclusive: z.boolean().optional().describe("When true, excludes the start date from results (uses > instead of >=)"), endExclusive: z.boolean().optional().describe("When true, excludes the end date from results (uses < instead of <=)") }).describe("Date range filter for timestamps"); const sortDirectionSchema = z.enum(["ASC", "DESC"]).describe("Sort direction: 'ASC' | 'DESC'"); /** Aggregation type schema shared across OLAP-style observability queries. */ const aggregationTypeSchema = z.enum([ "sum", "avg", "min", "max", "count", "count_distinct", "last" ]).describe("Aggregation function"); /** Aggregation interval schema shared across OLAP-style observability queries. */ const aggregationIntervalSchema = z.enum([ "1m", "5m", "15m", "1h", "1d" ]).describe("Time bucket interval"); /** Compare period for aggregate queries with period-over-period comparison. */ const comparePeriodSchema = 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 = z.array(z.string()).min(1).describe("Fields to group by"); /** Shared percentiles schema for percentile queries. */ const percentilesSchema = z.array(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: z.number().nullable().describe("Aggregated value"), previousValue: z.number().nullable().optional().describe("Value from comparison period"), changePercent: z.number().nullable().optional().describe("Percentage change from comparison period") }; /** Shared field for OLAP breakdown dimension values. */ const dimensionsField = z.record(z.string(), z.string().nullable()).describe("Dimension values for this group"); /** Shared field for non-null OLAP aggregated values. */ const aggregatedValueField = z.number().describe("Aggregated value"); /** Shared field for OLAP bucket timestamps. */ const bucketTimestampField = z.date().describe("Bucket timestamp"); /** Shared field for percentile identifiers in OLAP responses. */ const percentileField = z.number().describe("Percentile value"); /** Shared field for percentile values within a time bucket. */ const percentileBucketValueField = z.number().describe("Percentile value at this bucket"); const entityTypeField = z.nativeEnum(EntityType).describe(`Entity type (e.g., 'agent' | 'processor' | 'tool' | 'workflow')`); const entityIdField = z.string().describe("ID of the entity (e.g., \"weatherAgent\", \"orderWorkflow\")"); const entityNameField = z.string().describe("Name of the entity"); const userIdField = z.string().describe("Human end-user who triggered execution"); const organizationIdField = z.string().describe("Multi-tenant organization/account"); const resourceIdField = z.string().describe("Broader resource context (Mastra memory compatibility)"); const runIdField = z.string().describe("Unique execution run identifier"); const sessionIdField = z.string().describe("Session identifier for grouping traces"); const threadIdField = z.string().describe("Conversation thread identifier"); const requestIdField = z.string().describe("HTTP request ID for log correlation"); const environmentField = z.string().describe(`Environment (e.g., "production" | "staging" | "development")`); const sourceField = z.string().describe(`Source of execution (e.g., "local" | "cloud" | "ci")`); const executionSourceField = z.string().describe(`Source of execution (e.g., "local" | "cloud" | "ci")`); const serviceNameField = z.string().describe("Name of the service"); const parentEntityTypeField = z.nativeEnum(EntityType).describe("Entity type of the parent entity"); const parentEntityIdField = z.string().describe("ID of the parent entity"); const parentEntityNameField = z.string().describe("Name of the parent entity"); const rootEntityTypeField = z.nativeEnum(EntityType).describe("Entity type of the root entity"); const rootEntityIdField = z.string().describe("ID of the root entity"); const rootEntityNameField = z.string().describe("Name of the root entity"); const entityVersionIdField = z.string().describe("Version ID of the entity that produced this signal (e.g., agent version, workflow version)"); const parentEntityVersionIdField = z.string().describe("Version ID of the parent entity that produced this signal"); const rootEntityVersionIdField = z.string().describe("Version ID of the root entity that produced this signal"); const experimentIdField = z.string().describe("Experiment or eval run identifier"); const scopeField = z.record(z.string(), z.unknown()).describe("Arbitrary package/app version info (e.g., {\"core\": \"1.0.0\", \"memory\": \"1.0.0\", \"gitSha\": \"abcd1234\"})"); const metadataField = z.record(z.string(), z.unknown()).describe("User-defined metadata for custom filtering"); const tagsField = z.array(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: z.string().optional().describe("Filter by trace ID"), spanId: 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: z.array(z.string()).optional().describe("Filter by tags (must have all specified tags)") }; /** Zod schema for trace ID field */ const traceIdField = z.string().describe("Unique trace identifier"); /** Zod schema for span ID field */ const spanIdField = z.string().describe("Unique span identifier within a trace"); /** Log level schema for validation */ const logLevelSchema = z.enum([ "debug", "info", "warn", "error", "fatal" ]); const messageField = z.string().describe("Log message"); const logDataField = z.record(z.string(), 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 = z.object({ logId: z.string().nullish().describe("Unique id for this log event"), timestamp: 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: 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 = 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 = z.object({ logs: z.array(createLogRecordSchema) }).describe("Arguments for batch creating logs"); /** Schema for filtering logs in list queries */ const logsFilterSchema = z.object({ ...commonFilterFields, /** * @deprecated Use `executionSource` instead. */ source: z.string().optional().describe("Filter by execution source"), level: z.union([logLevelSchema, z.array(logLevelSchema)]).optional().describe("Filter by log level(s)") }).describe("Filters for querying logs"); /** Fields available for ordering log results */ const logsOrderByFieldSchema = z.enum(["timestamp"]).describe("Field to order by: 'timestamp'"); /** Order by configuration for log queries */ const logsOrderBySchema = 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 = 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 = z.object({ pagination: paginationInfoSchema.optional(), delta: deltaInfoSchema.optional(), deltaCursor: deltaCursorSchema.optional(), logs: z.array(logRecordSchema) }).describe("Response from listing logs"); const scorerIdField = z.string().describe("Identifier of the scorer (e.g., relevance, accuracy)"); const scorerNameField = z.string().describe("Display name of the scorer"); const scorerVersionField = z.string().describe("Version of the scorer"); const scoreSourceField = z.string().describe("How the score was produced (e.g., manual, automated, experiment)"); const scoreValueField = z.number().describe("Score value (range defined by scorer)"); const scoreReasonField = 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 = z.object({ scoreId: z.string().nullish().describe("Unique id for this score event"), timestamp: 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: z.string().nullish().describe("Trace ID of the scoring run for debugging score generation"), metadata: z.record(z.string(), 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 = 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: z.record(z.string(), z.unknown()).optional().describe("Additional scorer-specific metadata"), experimentId: experimentIdField.optional(), scoreTraceId: 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 = z.object({ score: createScoreRecordSchema }).describe("Arguments for creating a score"); /** Schema for createScore operation body in client/server */ const createScoreBodySchema = z.object({ score: createScoreRecordSchema.omit({ timestamp: true }) }).describe("Arguments for creating a score"); /** Schema for createScore operation response */ const createScoreResponseSchema = z.object({ success: z.boolean() }).describe("Response from creating a score"); /** Schema for batchCreateScores operation arguments */ const batchCreateScoresArgsSchema = z.object({ scores: z.array(createScoreRecordSchema) }).describe("Arguments for batch recording scores"); /** Schema for filtering scores in list queries */ const scoresFilterSchema = z.object({ ...commonFilterFields, scorerId: z.union([z.string(), z.array(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 = z.enum(["timestamp", "score"]).describe("Field to order by: 'timestamp' | 'score'"); /** Order by configuration for score queries */ const scoresOrderBySchema = z.object({ field: scoresOrderByFieldSchema.default("timestamp").describe("Field to order by"), direction: sortDirectionSchema.default("DESC").describe("Sort direction") }).describe("Order by configuration"); const listScoresArgsSchema = 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 = z.object({ pagination: paginationInfoSchema.optional(), delta: deltaInfoSchema.optional(), deltaCursor: deltaCursorSchema.optional(), scores: z.array(scoreRecordSchema) }).describe("Response from listing scores"); const getScoreAggregateArgsSchema = z.object({ scorerId: scorerIdField, scoreSource: scoreSourceField.optional(), aggregation: aggregationTypeSchema, filters: scoresFilterSchema.optional(), comparePeriod: comparePeriodSchema.optional() }).describe("Arguments for getting a score aggregate"); const getScoreAggregateResponseSchema = z.object(aggregateResponseFields); const getScoreBreakdownArgsSchema = z.object({ scorerId: scorerIdField, scoreSource: scoreSourceField.optional(), groupBy: groupBySchema, aggregation: aggregationTypeSchema, filters: scoresFilterSchema.optional() }).describe("Arguments for getting a score breakdown"); const getScoreBreakdownResponseSchema = z.object({ groups: z.array(z.object({ dimensions: dimensionsField, value: aggregatedValueField })) }); const getScoreTimeSeriesArgsSchema = 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 = z.object({ series: z.array(z.object({ name: z.string().describe("Series name (scorer ID or group key)"), points: z.array(z.object({ timestamp: bucketTimestampField, value: aggregatedValueField })) })) }); const getScorePercentilesArgsSchema = z.object({ scorerId: scorerIdField, scoreSource: scoreSourceField.optional(), percentiles: percentilesSchema, interval: aggregationIntervalSchema, filters: scoresFilterSchema.optional() }).describe("Arguments for getting score percentiles"); const getScorePercentilesResponseSchema = z.object({ series: z.array(z.object({ percentile: percentileField, points: z.array(z.object({ timestamp: bucketTimestampField, value: percentileBucketValueField })) })) }); const feedbackSourceField = z.string().describe("Source of feedback (e.g., 'user', 'system', 'manual')"); const feedbackTypeField = z.string().describe("Type of feedback (e.g., 'thumbs', 'rating', 'correction')"); const feedbackValueField = z.union([z.number(), z.string()]).describe("Feedback value (rating number or correction text)"); const feedbackCommentField = z.string().describe("Additional comment or context"); const feedbackUserIdField = 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 = z.object({ feedbackId: z.string().nullish().describe("Unique id for this feedback event"), timestamp: 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: z.string().nullish().describe("ID of the source record this feedback is linked to (e.g. experiment result ID)"), metadata: z.record(z.string(), z.unknown()).nullish().describe("User-defined metadata") }); const feedbackRecordSchema = 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 = 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: z.record(z.string(), z.unknown()).optional().describe("Additional feedback-specific metadata"), experimentId: experimentIdField.optional(), sourceId: z.string().optional().describe("ID of the source record this feedback is linked to") }); const feedbackInputSchema = 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 = z.object({ feedback: z.preprocess(normalizeLegacyFeedbackActor, feedbackRecordObjectSchema) }).describe("Arguments for creating feedback"); /** Schema for createFeedback operation body in client/server */ const createFeedbackBodySchema = z.object({ feedback: feedbackRecordObjectSchema.omit({ timestamp: true }) }).describe("Arguments for creating feedback"); /** Schema for createFeedback operation response */ const createFeedbackResponseSchema = z.object({ success: z.boolean() }).describe("Response from creating feedback"); /** Schema for batchCreateFeedback operation arguments */ const batchCreateFeedbackArgsSchema = z.object({ feedbacks: z.array(z.preprocess(normalizeLegacyFeedbackActor, feedbackRecordObjectSchema)) }).describe("Arguments for batch recording feedback"); /** Schema for filtering feedback in list queries */ const feedbackFilterObjectSchema = z.object({ ...commonFilterFields, feedbackType: z.union([z.string(), z.array(z.string())]).optional().describe("Filter by feedback type(s)"), feedbackSource: feedbackSourceField.optional(), /** * @deprecated Use `feedbackSource` instead. */ source: feedbackSourceField.optional(), feedbackUserId: feedbackUserIdField.optional() }); const feedbackFilterSchema = z.object(feedbackFilterObjectSchema.shape).describe("Filters for querying feedback"); /** Fields available for ordering feedback results */ const feedbackOrderByFieldSchema = z.enum(["timestamp"]).describe("Field to order by: 'timestamp'"); /** Order by configuration for feedback queries */ const feedbackOrderBySchema = z.object({ field: feedbackOrderByFieldSchema.default("timestamp").describe("Field to order by"), direction: sortDirectionSchema.default("DESC").describe("Sort direction") }).describe("Order by configuration"); const listFeedbackArgsSchema = z.object({ mode: listModeSchema.optional(), filters: 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 = z.object({ pagination: paginationInfoSchema.optional(), delta: deltaInfoSchema.optional(), deltaCursor: deltaCursorSchema.optional(), feedback: z.array(feedbackRecordSchema) }).describe("Response from listing feedback"); const getFeedbackAggregateArgsSchema = 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 = z.object(aggregateResponseFields); const getFeedbackBreakdownArgsSchema = 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 = z.object({ groups: z.array(z.object({ dimensions: dimensionsField, value: aggregatedValueField })) }); const getFeedbackTimeSeriesArgsSchema = 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 = z.object({ series: z.array(z.object({ name: z.string().describe("Series name (feedback type or group key)"), points: z.array(z.object({ timestamp: bucketTimestampField, value: aggregatedValueField })) })) }); const getFeedbackPercentilesArgsSchema = 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 = z.object({ series: z.array(z.object({ percentile: percentileField, points: z.array(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 = z.enum([ "counter", "gauge", "histogram" ]); const metricNameField = z.string().describe("Metric name (e.g., mastra_agent_duration_ms)"); const metricValueField = z.number().describe("Metric value"); const labelsField = z.record(z.string(), z.string()).describe("Metric labels for dimensional filtering"); const providerField = z.string().describe("Model provider"); const modelField = z.string().describe("Model"); const estimatedCostField = z.number().describe("Estimated cost"); const costUnitField = z.string().describe("Unit for the estimated cost (e.g., usd)"); const costMetadField = z.record(z.string(), z.unknown()).nullish().describe("Structured costing metadata"); /** * Schema for metrics as stored in the database. * Each record is a single metric observation. */ const metricRecordSchema = z.object({ metricId: z.string().nullish().describe("Unique id for this metric event"), timestamp: z.date().describe("When the metric was recorded"), name: metricNameField, value: metricValueField, traceId: traceIdField.nullish(), spanId: spanIdField.nullish(), ...contextFields, /** * @deprecated Use `executionSource` instead. */ source: 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 = 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 = z.object({ metrics: z.array(createMetricRecordSchema) }).describe("Arguments for batch recording metrics"); /** Schema for metric aggregation configuration */ const metricsAggregationSchema = z.object({ type: aggregationTypeSchema, interval: aggregationIntervalSchema.optional(), groupBy: groupBySchema.optional() }).describe("Metrics aggregation configuration"); /** Schema for filtering metrics in queries */ const metricsFilterSchema = z.object({ ...commonFilterFields, traceIds: z.array(traceIdField).nonempty().max(1e3).optional().describe("Filter by one or more trace IDs"), name: z.array(z.string()).nonempty().optional().describe("Filter by metric name(s)"), /** * @deprecated Use `executionSource` instead. */ source: z.string().optional().describe("Filter by execution source"), provider: providerField.optional(), model: modelField.optional(), costUnit: costUnitField.optional(), labels: z.record(z.string(), 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 = z.enum(["timestamp"]).describe("Field to order by: 'timestamp'"); /** Order by configuration for metric list queries */ const metricsOrderBySchema = z.object({ field: metricsOrderByFieldSchema.default("timestamp").describe("Field to order by"), direction: sortDirectionSchema.default("DESC").describe("Sort direction") }).describe("Order by configuration"); const listMetricsArgsSchema = 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 = z.object({ pagination: paginationInfoSchema.optional(), delta: deltaInfoSchema.optional(), deltaCursor: deltaCursorSchema.optional(), metrics: 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 = 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 = z.object({ name: z.array(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 = z.object({ ...aggregateResponseFields, estimatedCost: z.number().nullable().optional().describe("Aggregated estimated cost from the same filtered row set"), costUnit: z.string().nullable().optional().describe("Shared cost unit for the aggregated rows, or null when mixed/unknown"), previousEstimatedCost: z.number().nullable().optional().describe("Aggregated estimated cost from the comparison period"), costChangePercent: z.number().nullable().optional().describe("Percentage change in estimated cost from comparison period") }); const getMetricBreakdownArgsSchema = z.object({ name: z.array(z.string()).nonempty().describe("Metric name(s) to break down"), groupBy: groupBySchema, aggregation: aggregationTypeSchema, distinctColumn: distinctColumnSchema, filters: metricsFilterSchema.optional(), limit: 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 = z.object({ groups: z.array(z.object({ dimensions: dimensionsField, value: aggregatedValueField, estimatedCost: z.number().nullable().optional().describe("Summed estimated cost for this group"), costUnit: z.string().nullable().optional().describe("Shared cost unit for this group, or null when mixed/unknown") })) }); const getMetricTimeSeriesArgsSchema = z.object({ name: z.array(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 = z.object({ series: z.array(z.object({ name: z.string().describe("Series name (metric name or group key)"), costUnit: z.string().nullable().optional().describe("Shared cost unit for this series, or null when mixed/unknown"), points: z.array(z.object({ timestamp: bucketTimestampField, value: aggregatedValueField, estimatedCost: z.number().nullable().optional().describe("Summed estimated cost in this bucket") })) })) }); const getMetricPercentilesArgsSchema = z.object({ name: z.string().describe("Metric name"), percentiles: percentilesSchema, interval: aggregationIntervalSchema, filters: metricsFilterSchema.optional() }).describe("Arguments for getting metric percentiles"); const getMetricPercentilesResponseSchema = z.object({ series: z.array(z.object({ percentile: percentileField, points: z.array(z.object({ timestamp: bucketTimestampField, value: percentileBucketValueField })) })) }); const getMetricNamesArgsSchema = z.object({ prefix: z.string().optional().describe("Filter metric names by prefix"), limit: z.coerce.number().int().min(1).optional().describe("Maximum number of names to return") }).describe("Arguments for getting metric names"); const getMetricNamesResponseSchema = z.object({ names: z.array(z.string()).describe("Distinct metric names") }); const getMetricLabelKeysArgsSchema = z.object({ metricName: z.string().describe("Metric name to get label keys for") }).describe("Arguments for getting metric label keys"); const getMetricLabelKeysResponseSchema = z.object({ keys: z.array(z.string()).describe("Distinct label keys for the metric") }); const getMetricLabelValuesArgsSchema = z.object({ metricName: z.string().describe("Metric name"), labelKey: z.string().describe("Label key to get values for"), prefix: z.string().optional().describe("Filter values by prefix"), limit: z.coerce.number().int().min(1).optional().describe("Maximum number of values to return") }).describe("Arguments for getting label values"); const getMetricLabelValuesResponseSchema = z.object({ values: z.array(z.string()).describe("Distinct label values") }); const getEntityTypesArgsSchema = z.object({}).describe("Arguments for getting entity types"); const getEntityTypesResponseSchema = z.object({ entityTypes: z.array(entityTypeField).describe("Distinct entity types") }); const getEntityNamesArgsSchema = z.object({ entityType: entityTypeField.optional().describe("Optional entity type filter") }).describe("Arguments for getting entity names"); const getEntityNamesResponseSchema = z.object({ names: z.array(z.string()).describe("Distinct entity names") }); const getServiceNamesArgsSchema = z.object({}).describe("Arguments for getting service names"); const getServiceNamesResponseSchema = z.object({ serviceNames: z.array(z.string()).describe("Distinct service names") }); const getEnvironmentsArgsSchema = z.object({}).describe("Arguments for getting environments"); const getEnvironmentsResponseSchema = z.object({ environments: z.array(z.string()).describe("Distinct environments") }); const getTagsArgsSchema = z.object({ entityType: entityTypeField.optional().describe("Optional entity type filter") }).describe("Arguments for getting tags"); const getTagsResponseSchema = z.object({ tags: z.array(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.WORKFLOW_STEP; case "tool_call": case "mcp_tool_call": case "provider_tool_call": return EntityType.TOOL; case "processor_run": return EntityType.OUTPUT_PROCESSOR; default: return; } } //#endregion export { getEntityNamesArgsSchema as $, logsOrderBySchema as $t, createScoreBodySchema as A, sortDirectionSchema as An, getScoreBreakdownResponseSchema as At, deltaLimitSchema as B, listFeedbackResponseSchema as Bt, createFeedbackArgsSchema as C, scoreInputSchema as Cn, getMetricPercentilesArgsSchema as Ct, createLogRecordSchema as D, scoresOrderBySchema as Dn, getScoreAggregateArgsSchema as Dt, createFeedbackResponseSchema as E, scoresOrderByFieldSchema as En, getMetricTimeSeriesResponseSchema as Et, dbTimestamps as F, threadIdField as Fn, getServiceNamesArgsSchema as Ft, environmentField as G, listModeSchema as Gt, entityIdField as H, listLogsResponseSchema as Ht, defaultDeltaLimit as I, traceIdField as In, getServiceNamesResponseSchema as It, feedbackFilterSchema as J, logLevelSchema as Jt, executionSourceField as K, listScoresArgsSchema as Kt, defaultPaginationArgs as L, updatedAtField as Ln, getTagsArgsSchema as Lt, createScoreResponseSchema as M, spanContextFields as Mn, getScorePercentilesResponseSchema as Mt, createdAtField as N, spanIdField as Nn, getScoreTimeSeriesArgsSchema as Nt, createMetricRecordSchema as O, serviceNameField as On, getScoreAggregateResponseSchema as Ot, dateRangeSchema as P, tagsField as Pn, getScoreTimeSeriesResponseSchema as Pt, feedbackRecordSchema as Q, logsOrderByFieldSchema as Qt, deltaCursorSchema as R, userIdField as Rn, getTagsResponseSchema as Rt, contextFields as S, scopeField as Sn, getMetricNamesResponseSchema as St, createFeedbackRecordSchema as T, scoresFilterSchema as Tn, getMetricTimeSeriesArgsSchema as Tt, entityNameField as U, listMetricsArgsSchema as Ut, distinctColumnSchema as V, listLogsArgsSchema as Vt, entityTypeField as W, listMetricsResponseSchema as Wt, feedbackOrderByFieldSchema as X, logRecordSchema as Xt, feedbackInputSchema as Y, logRecordInputSchema as Yt, feedbackOrderBySchema as Z, logsFilterSchema as Zt, batchCreateLogsArgsSchema as _, resourceIdField as _n, getMetricLabelKeysArgsSchema as _t, getOrCreateSpan as a, metricsFilterSchema as an, getFe