UNPKG

@mastra/core

Version:
1,864 lines 88.1 kB
const require_utils = require("./utils-CNiGU0Uf.cjs"); const require_tracing = require("./tracing-BUrUJwCM.cjs"); const require_zod_utils = require("./zod-utils-BAGXGqPm.cjs"); let zod_v4 = require("zod/v4"); //#region src/evals/types.ts const scoringSourceSchema = zod_v4.z.enum(["LIVE", "TEST"]); const scoringEntityTypeSchema = zod_v4.z.enum([ "AGENT", "WORKFLOW", "TRAJECTORY", "STEP", ...Object.values(require_tracing.SpanType) ]); const scoringPromptsSchema = zod_v4.z.object({ description: zod_v4.z.string(), prompt: zod_v4.z.string() }); /** Reusable schema for required record fields (e.g., scorer, entity) */ const recordSchema = zod_v4.z.record(zod_v4.z.string(), zod_v4.z.unknown()); /** Reusable schema for optional record fields (e.g., metadata, additionalContext) */ const optionalRecordSchema = recordSchema.optional(); const scoringInputSchema = zod_v4.z.object({ runId: zod_v4.z.string().optional(), input: zod_v4.z.unknown().optional(), output: zod_v4.z.unknown(), additionalContext: optionalRecordSchema, requestContext: optionalRecordSchema }); const scoringHookInputSchema = zod_v4.z.object({ runId: zod_v4.z.string().optional(), scorer: recordSchema, input: zod_v4.z.unknown(), output: zod_v4.z.unknown(), metadata: optionalRecordSchema, additionalContext: optionalRecordSchema, source: scoringSourceSchema, entity: recordSchema, entityType: scoringEntityTypeSchema, requestContext: optionalRecordSchema, structuredOutput: zod_v4.z.boolean().optional(), traceId: zod_v4.z.string().optional(), spanId: zod_v4.z.string().optional(), resourceId: zod_v4.z.string().optional(), threadId: zod_v4.z.string().optional(), projectId: zod_v4.z.string().optional() }); const scoringExtractStepResultSchema = optionalRecordSchema; const scoringValueSchema = zod_v4.z.number(); const scoreResultSchema = zod_v4.z.object({ result: optionalRecordSchema, score: scoringValueSchema, prompt: zod_v4.z.string().optional() }); const scoringInputWithExtractStepResultSchema = scoringInputSchema.extend({ runId: zod_v4.z.string(), extractStepResult: optionalRecordSchema, extractPrompt: zod_v4.z.string().optional() }); const scoringInputWithExtractStepResultAndAnalyzeStepResultSchema = scoringInputWithExtractStepResultSchema.extend({ score: zod_v4.z.number(), analyzeStepResult: optionalRecordSchema, analyzePrompt: zod_v4.z.string().optional() }); const scoringInputWithExtractStepResultAndScoreAndReasonSchema = scoringInputWithExtractStepResultAndAnalyzeStepResultSchema.extend({ reason: zod_v4.z.string().optional(), reasonPrompt: zod_v4.z.string().optional() }); const scoreRowDataSchema = zod_v4.z.object({ id: zod_v4.z.string(), scorerId: zod_v4.z.string(), entityId: zod_v4.z.string(), runId: zod_v4.z.string(), input: zod_v4.z.unknown().optional(), output: zod_v4.z.unknown(), additionalContext: optionalRecordSchema, requestContext: optionalRecordSchema, extractStepResult: optionalRecordSchema, extractPrompt: zod_v4.z.string().optional(), score: zod_v4.z.number(), analyzeStepResult: optionalRecordSchema, analyzePrompt: zod_v4.z.string().optional(), reason: zod_v4.z.string().optional(), reasonPrompt: zod_v4.z.string().optional(), scorer: recordSchema, metadata: optionalRecordSchema, source: scoringSourceSchema, entity: recordSchema, entityType: scoringEntityTypeSchema.optional(), structuredOutput: zod_v4.z.boolean().optional(), traceId: zod_v4.z.string().optional(), spanId: zod_v4.z.string().optional(), resourceId: zod_v4.z.string().optional(), threadId: zod_v4.z.string().optional(), organizationId: zod_v4.z.string().nullish(), projectId: zod_v4.z.string().nullish(), batchId: zod_v4.z.string().nullish(), datasetId: zod_v4.z.string().nullish(), datasetItemId: zod_v4.z.string().nullish(), preprocessStepResult: optionalRecordSchema, preprocessPrompt: zod_v4.z.string().optional(), generateScorePrompt: zod_v4.z.string().optional(), generateReasonPrompt: zod_v4.z.string().optional(), ...require_utils.dbTimestamps }); const saveScorePayloadSchema = scoreRowDataSchema.omit({ id: true, createdAt: true, updatedAt: true }); const listScoresResponseSchema = zod_v4.z.object({ pagination: require_utils.paginationInfoSchema, scores: zod_v4.z.array(scoreRowDataSchema) }); /** * Extracts a Trajectory from agent output messages by walking through * tool invocations. * * This is called automatically by `runEvals` when using `AgentScorerConfig.trajectory` * scorers — trajectory scorers receive a pre-extracted `Trajectory` as their `output` * instead of raw `MastraDBMessage[]`. * * @param output - The raw agent output messages * @returns A Trajectory with ToolCallStep entries extracted from tool invocations */ function extractTrajectory(output) { const steps = []; for (const message of output) { const legacy = message?.content?.toolInvocations; const fromParts = legacy ? void 0 : message?.content?.parts?.filter((p) => p.type === "tool-invocation").map((p) => p.toolInvocation); const toolInvocations = legacy ?? fromParts; if (!toolInvocations?.length) continue; for (const invocation of toolInvocations) if (invocation && invocation.toolName && (invocation.state === "result" || invocation.state === "call")) { const toolArgs = invocation.args != null && typeof invocation.args === "object" && !Array.isArray(invocation.args) ? invocation.args : invocation.args != null ? { value: invocation.args } : void 0; const rawResult = invocation.state === "result" ? invocation.result : void 0; const toolResult = rawResult != null && typeof rawResult === "object" && !Array.isArray(rawResult) ? rawResult : rawResult != null ? { value: rawResult } : void 0; steps.push({ stepType: "tool_call", name: invocation.toolName, toolArgs, toolResult, success: invocation.state === "result" }); } } return { steps, rawOutput: output }; } /** * Extracts a Trajectory from workflow step results. * * Converts the `stepResults` record (and optional `stepExecutionPath` ordering) * into a flat list of `WorkflowStepStep` entries. Each step captures its status, * output, and timing. * * This is called automatically by `runEvals` when using `WorkflowScorerConfig.trajectory` * scorers. * * @param stepResults - The workflow step results record * @param stepExecutionPath - Optional ordered list of step IDs for execution ordering * @returns A Trajectory with WorkflowStepStep entries */ function extractWorkflowTrajectory(stepResults, stepExecutionPath) { const steps = []; const stepIds = stepExecutionPath ?? Object.keys(stepResults); let totalStartedAt; let totalEndedAt; for (const stepId of stepIds) { const result = stepResults[stepId]; if (!result) continue; if (result.startedAt != null) { if (totalStartedAt == null || result.startedAt < totalStartedAt) totalStartedAt = result.startedAt; } const endedAt = "endedAt" in result ? result.endedAt : void 0; if (endedAt != null) { if (totalEndedAt == null || endedAt > totalEndedAt) totalEndedAt = endedAt; } const durationMs = result.startedAt != null && endedAt != null ? endedAt - result.startedAt : void 0; const output = "output" in result && result.output != null && typeof result.output === "object" && !Array.isArray(result.output) ? result.output : "output" in result && result.output != null ? { value: result.output } : void 0; steps.push({ stepType: "workflow_step", name: stepId, stepId, status: result.status, output, durationMs, metadata: result.metadata }); } return { steps, totalDurationMs: totalStartedAt != null && totalEndedAt != null ? totalEndedAt - totalStartedAt : void 0, rawWorkflowResult: { stepResults, stepExecutionPath } }; } /** * Span types that are considered noise and should be skipped during * trace-to-trajectory conversion (internal implementation details, not * meaningful trajectory steps). */ const SKIPPED_SPAN_TYPES = /* @__PURE__ */ new Set([ "scorer_run", "scorer_step", "generic", "model_step", "model_inference", "model_chunk", "workflow_conditional_eval" ]); /** * Converts a `SpanTreeNode` to `TrajectoryStep` entries. * * Returns an array because a skipped span promotes its children into the * parent's list rather than dropping them entirely. */ function spanToTrajectorySteps(node) { const { span, children: childNodes } = node; if (SKIPPED_SPAN_TYPES.has(span.spanType)) return childNodes.flatMap(spanToTrajectorySteps); const durationMs = span.endedAt != null && span.startedAt != null ? span.endedAt.getTime() - span.startedAt.getTime() : void 0; const childSteps = childNodes.flatMap(spanToTrajectorySteps); const base = { name: span.name, durationMs, metadata: span.metadata, ...childSteps.length > 0 ? { children: childSteps } : {} }; const attrs = span.attributes ?? {}; switch (span.spanType) { case "tool_call": { const toolArgs = toRecordOrUndefined(span.input); const toolResult = toRecordOrUndefined(span.output); return [{ ...base, stepType: "tool_call", toolArgs, toolResult, success: typeof attrs.success === "boolean" ? attrs.success : void 0 }]; } case "mcp_tool_call": { const toolArgs = toRecordOrUndefined(span.input); const toolResult = toRecordOrUndefined(span.output); return [{ ...base, stepType: "mcp_tool_call", toolArgs, toolResult, mcpServer: typeof attrs.mcpServer === "string" ? attrs.mcpServer : void 0, success: typeof attrs.success === "boolean" ? attrs.success : void 0 }]; } case "provider_tool_call": { const toolArgs = toRecordOrUndefined(span.input); const toolResult = toRecordOrUndefined(span.output); return [{ ...base, stepType: "provider_tool_call", toolArgs, toolResult, success: typeof attrs.success === "boolean" ? attrs.success : void 0 }]; } case "model_generation": { const usage = attrs.usage; return [{ ...base, stepType: "model_generation", modelId: typeof attrs.model === "string" ? attrs.model : void 0, promptTokens: usage?.inputTokens, completionTokens: usage?.outputTokens, finishReason: typeof attrs.finishReason === "string" ? attrs.finishReason : void 0 }]; } case "agent_run": return [{ ...base, stepType: "agent_run", agentId: span.entityId ?? void 0 }]; case "workflow_run": return [{ ...base, stepType: "workflow_run", workflowId: span.entityId ?? void 0 }]; case "workflow_step": { const output = toRecordOrUndefined(span.output); return [{ ...base, stepType: "workflow_step", stepId: span.name, output }]; } case "workflow_conditional": return [{ ...base, stepType: "workflow_conditional" }]; case "workflow_parallel": return [{ ...base, stepType: "workflow_parallel" }]; case "workflow_loop": return [{ ...base, stepType: "workflow_loop" }]; case "workflow_sleep": return [{ ...base, stepType: "workflow_sleep" }]; case "workflow_wait_event": return [{ ...base, stepType: "workflow_wait_event" }]; case "processor_run": return [{ ...base, stepType: "processor_run" }]; default: return childSteps; } } /** * Safely converts a value to `Record<string, unknown>` or returns undefined. */ function toRecordOrUndefined(value) { if (value == null) return void 0; if (typeof value === "object" && !Array.isArray(value)) return value; return { value }; } /** * Extracts a hierarchical Trajectory from trace spans (as returned by the * observability store's `getTrace()`). * * Builds a parent-child tree from `parentSpanId` references, then recursively * converts each span to the appropriate `TrajectoryStep` discriminated union * type with nested `children`. * * Noise spans (`generic`, `model_step`, `model_chunk`, `workflow_conditional_eval`) * are automatically skipped. * * This is used by `runEvals` when storage is available to produce richer, * hierarchical trajectories that include nested agent runs, tool calls, and * model generations inside workflow or agent steps. * * @param spans - Flat array of span records from `getTrace().spans` * @param rootSpanId - Optional span ID to use as root. If omitted, spans with * no parent are used as roots. * @returns A Trajectory with hierarchical TrajectoryStep entries * * @example * ```ts * const trace = await observabilityStore.getTrace({ traceId }); * const trajectory = extractTrajectoryFromTrace(trace.spans, workflowSpanId); * ``` */ function extractTrajectoryFromTrace(spans, rootSpanId) { if (spans.length === 0) return { steps: [] }; const nodeMap = /* @__PURE__ */ new Map(); for (const span of spans) nodeMap.set(span.spanId, { span, children: [] }); const roots = []; for (const span of spans) { const node = nodeMap.get(span.spanId); if (span.parentSpanId && nodeMap.has(span.parentSpanId)) nodeMap.get(span.parentSpanId).children.push(node); else roots.push(node); } for (const node of nodeMap.values()) node.children.sort((a, b) => a.span.startedAt.getTime() - b.span.startedAt.getTime()); let targetRoots; if (rootSpanId) { const rootNode = nodeMap.get(rootSpanId); targetRoots = rootNode ? [rootNode] : roots; } else targetRoots = roots; let stepsToConvert; if (targetRoots.length === 1) { const root = targetRoots[0]; if ((/* @__PURE__ */ new Set(["workflow_run", "agent_run"])).has(root.span.spanType)) stepsToConvert = root.children; else stepsToConvert = targetRoots; } else stepsToConvert = targetRoots; const steps = stepsToConvert.flatMap(spanToTrajectorySteps); let totalDurationMs; if (targetRoots.length === 1) { const root = targetRoots[0].span; if (root.endedAt && root.startedAt) totalDurationMs = root.endedAt.getTime() - root.startedAt.getTime(); } return { steps, totalDurationMs }; } //#endregion //#region src/storage/types.ts const STORAGE_VISIBILITY_VALUES = ["private", "public"]; function unwrapSchema(schema) { let current = schema; let nullable = false; while (true) { const typeName = require_zod_utils.getZodTypeName(current); if (!typeName) break; if (typeName === "ZodNullable" || typeName === "ZodOptional") nullable = true; const inner = require_zod_utils.getZodInnerType(current, typeName); if (!inner) break; current = inner; } return { base: current, nullable }; } /** * Extract checks array from Zod schema, compatible with both Zod 3 and Zod 4. * Zod 3 uses _def.checks with {kind: "..."} objects * Zod 4 uses _zod.def.checks with {def: {check: "...", format: "..."}} objects */ function getZodChecks(schema) { if ("_zod" in schema) { const checks = schema._zod?.def?.checks; if (checks && Array.isArray(checks)) return checks.map((check) => { if (typeof check === "object" && check !== null && "def" in check && typeof check.def === "object" && check.def !== null) { const def = check.def; if (def.check === "number_format" && def.format === "safeint") return { kind: "int" }; if (def.check === "string_format" && typeof def.format === "string") return { kind: def.format }; return { kind: typeof def.check === "string" ? def.check : "unknown" }; } return { kind: "unknown" }; }); } if ("_def" in schema) { const checks = schema._def?.checks; if (checks && Array.isArray(checks)) return checks; } return []; } function zodToStorageType(schema) { const typeName = require_zod_utils.getZodTypeName(schema); if (typeName === "ZodString") { if (getZodChecks(schema).some((c) => c.kind === "uuid")) return "uuid"; return "text"; } if (typeName === "ZodNativeEnum" || typeName === "ZodEnum") return "text"; if (typeName === "ZodNumber") return getZodChecks(schema).some((c) => c.kind === "int") ? "integer" : "float"; if (typeName === "ZodBigInt" || typeName === "ZodBigint") return "bigint"; if (typeName === "ZodDate") return "timestamp"; if (typeName === "ZodBoolean") return "boolean"; return "jsonb"; } /** * Converts a zod schema into a database schema * @param zObject A zod schema object * @returns database schema record with StorageColumns */ function buildStorageSchema(zObject) { const shape = zObject.shape; const result = {}; for (const [key, field] of Object.entries(shape)) { const { base, nullable } = unwrapSchema(field); result[key] = { type: zodToStorageType(base), nullable }; } return result; } const STORAGE_FAVORITE_ENTITY_TYPES = ["agent", "skill"]; //#endregion //#region src/storage/domains/observability/tracing.ts /** * Creates an omit key object from a Zod schema shape. * This allows dynamically deriving omit keys from existing schema definitions. */ const createOmitKeys = (shape) => Object.fromEntries(Object.keys(shape).map((k) => [k, true])); const spanNameField = zod_v4.z.string().describe("Human-readable span name"); const parentSpanIdField = zod_v4.z.string().describe("Parent span reference (null = root span)"); const spanTypeField = zod_v4.z.nativeEnum(require_tracing.SpanType).describe("Span type (e.g., WORKFLOW_RUN, AGENT_RUN, TOOL_CALL, etc.)"); const attributesField = zod_v4.z.record(zod_v4.z.string(), zod_v4.z.unknown()).describe("Span-type specific attributes (e.g., model, tokens, tools)"); const linksField = zod_v4.z.array(zod_v4.z.unknown()).describe("References to related spans in other traces"); const inputField = zod_v4.z.unknown().describe("Input data passed to the span"); const outputField = zod_v4.z.unknown().describe("Output data returned from the span"); const errorField = zod_v4.z.unknown().describe("Error info - presence indicates failure (status derived from this)"); const isEventField = zod_v4.z.boolean().describe("Whether this is an event (point-in-time) vs a span (duration)"); const startedAtField = zod_v4.z.date().describe("When the span started"); const endedAtField = zod_v4.z.date().describe("When the span ended (null = running, status derived from this)"); /** Derived status of a trace, computed from the root span's error and endedAt fields. */ let TraceStatus = /* @__PURE__ */ function(TraceStatus) { TraceStatus["SUCCESS"] = "success"; TraceStatus["ERROR"] = "error"; TraceStatus["RUNNING"] = "running"; return TraceStatus; }({}); const traceStatusField = zod_v4.z.nativeEnum(TraceStatus).describe("Current status of the trace"); const hasChildErrorField = zod_v4.z.preprocess((v) => { if (v === "true") return true; if (v === "false") return false; return v; }, zod_v4.z.boolean()).describe("True if any span in the trace encountered an error"); /** * All optional fields shared between span records and trace filters. * Built from spanContextFields plus span-specific metadata/tags. * Note: When filtering traces, these fields are matched against the root span. */ const sharedFields = { ...require_utils.spanContextFields, metadata: require_utils.metadataField.nullish(), tags: require_utils.tagsField.nullish() }; /** Shape containing trace and span identifier fields */ const spanIds = { traceId: require_utils.traceIdField, spanId: require_utils.spanIdField }; /** Schema for span identifiers (traceId and spanId) */ const spanIdsSchema = zod_v4.z.object({ ...spanIds }); const omitDbTimestamps = createOmitKeys(require_utils.dbTimestamps); const omitSpanIds = createOmitKeys(spanIds); /** Schema for a complete span record as stored in the database */ const spanRecordSchema = zod_v4.z.object({ ...spanIds, name: spanNameField, spanType: spanTypeField, isEvent: isEventField, startedAt: startedAtField, parentSpanId: parentSpanIdField.nullish(), ...sharedFields, experimentId: zod_v4.z.string().nullish().describe("Experiment or eval run identifier"), attributes: attributesField.nullish(), links: linksField.nullish(), input: inputField.nullish(), output: outputField.nullish(), error: errorField.nullish(), endedAt: endedAtField.nullish(), requestContext: zod_v4.z.record(zod_v4.z.string(), zod_v4.z.unknown()).nullish().describe("Request context data"), ...require_utils.dbTimestamps }).describe("Span record data"); /** * Computes the trace status from a root span's error and endedAt fields. * - ERROR: if error is present (regardless of endedAt) * - RUNNING: if endedAt is null/undefined and no error * - SUCCESS: if endedAt is present and no error */ function computeTraceStatus(span) { if (span.error != null) return "error"; if (span.endedAt == null) return "running"; return "success"; } /** Schema for a trace span (root span with computed status) */ const traceSpanSchema = spanRecordSchema.extend({ status: traceStatusField }).describe("Trace span with computed status (root spans only)"); /** * Converts a SpanRecord to a TraceSpan by adding computed status. * Used when returning root spans from listTraces. */ function toTraceSpan(span) { return { ...span, status: computeTraceStatus(span) }; } /** * Converts an array of SpanRecords to TraceSpans by adding computed status. * Used when returning root spans from listTraces. */ function toTraceSpans(spans) { return spans.map(toTraceSpan); } /** * Schema for creating a span (without db timestamps) */ const createSpanRecordSchema = spanRecordSchema.omit(omitDbTimestamps); /** * Schema for createSpan operation arguments */ const createSpanArgsSchema = zod_v4.z.object({ span: createSpanRecordSchema }).describe("Arguments for creating a single span"); /** * Schema for batchCreateSpans operation arguments */ const batchCreateSpansArgsSchema = zod_v4.z.object({ records: zod_v4.z.array(createSpanRecordSchema) }).describe("Arguments for batch creating spans"); /** * Schema for getSpan operation arguments */ const getSpanArgsSchema = zod_v4.z.object({ traceId: require_utils.traceIdField.min(1), spanId: require_utils.spanIdField.min(1) }).describe("Arguments for getting a single span"); /** * Response schema for getSpan operation */ const getSpanResponseSchema = zod_v4.z.object({ span: spanRecordSchema }); /** * Schema for getSpans (batch) operation arguments. * * Fetches multiple spans in a trace by spanId in one call. Used to power the * progressive-disclosure path in {@link getBranchArgsSchema}: walk the * lightweight {@link getStructureResponseSchema} to find which spanIds belong * to a branch, then fetch only those with full data instead of pulling the * entire trace. */ const getSpansArgsSchema = zod_v4.z.object({ traceId: require_utils.traceIdField.min(1), spanIds: zod_v4.z.array(require_utils.spanIdField.min(1)).min(1).describe("Span IDs to fetch within the trace") }).describe("Arguments for batch-fetching spans by spanId within a trace"); /** Response schema for getSpans operation */ const getSpansResponseSchema = zod_v4.z.object({ traceId: require_utils.traceIdField, spans: zod_v4.z.array(spanRecordSchema) }); /** * Schema for getRootSpan operation arguments */ const getRootSpanArgsSchema = zod_v4.z.object({ traceId: require_utils.traceIdField.min(1) }).describe("Arguments for getting a root span"); /** * Response schema for getRootSpan operation */ const getRootSpanResponseSchema = zod_v4.z.object({ span: spanRecordSchema }); /** * Schema for getTrace operation arguments */ const getTraceArgsSchema = zod_v4.z.object({ traceId: require_utils.traceIdField.min(1) }).describe("Arguments for getting a single trace"); /** * Response schema for getTrace operation */ const getTraceResponseSchema = zod_v4.z.object({ traceId: require_utils.traceIdField, spans: zod_v4.z.array(spanRecordSchema) }); /** * Schema for getBranch operation arguments. * * Returns the subtree rooted at `spanId`. When `depth` is omitted the full * descendant subtree is returned; with a finite `depth` only that many levels * below the anchor are returned (depth: 0 → only the anchor span; depth: 1 → * anchor plus immediate children; etc). */ const getBranchArgsSchema = zod_v4.z.object({ traceId: require_utils.traceIdField.min(1), spanId: require_utils.spanIdField.min(1), depth: zod_v4.z.coerce.number().int().min(0).optional().describe("Maximum descendant levels below the anchor span (omit for full subtree)") }).describe("Arguments for getting a span branch (subtree rooted at a span)"); /** * Response schema for getBranch operation. Mirrors getTrace -- a flat list of * spans, traversal-agnostic. The anchor span is included as the first matching * span; callers reconstruct the tree via parentSpanId. */ const getBranchResponseSchema = zod_v4.z.object({ traceId: require_utils.traceIdField, spans: zod_v4.z.array(spanRecordSchema) }); /** * Extracts the subtree rooted at `anchorSpanId` from a flat list of trace * spans. The anchor itself is included as the first element; descendants are * walked via `parentSpanId` and returned sorted by `startedAt` ascending after * the anchor. When `maxDepth` is provided, only that many levels of * descendants are returned (anchor counts as depth 0). * * Cycles in `parentSpanId` (which shouldn't happen in well-formed traces but * could surface from corrupted data) are handled by tracking visited spanIds * and skipping any span seen during this walk. * * Returns an empty array if the anchor isn't in the input. * * Generic over the span shape so it works on both full {@link SpanRecord} * lists (e.g. result of `getTrace`) and lightweight skeletons (result of * `getStructure`). */ function extractBranchSpans(spans, anchorSpanId, maxDepth) { const anchor = spans.find((s) => s.spanId === anchorSpanId); if (!anchor) return []; const childrenByParent = /* @__PURE__ */ new Map(); for (const span of spans) { if (span.parentSpanId == null) continue; const bucket = childrenByParent.get(span.parentSpanId); if (bucket) bucket.push(span); else childrenByParent.set(span.parentSpanId, [span]); } const visited = /* @__PURE__ */ new Set([anchor.spanId]); const descendants = []; let frontier = [anchor]; let depth = 0; while (frontier.length > 0) { if (maxDepth != null && depth >= maxDepth) break; const next = []; for (const span of frontier) { const children = childrenByParent.get(span.spanId); if (!children) continue; for (const child of children) { if (visited.has(child.spanId)) continue; visited.add(child.spanId); descendants.push(child); next.push(child); } } frontier = next; depth++; } descendants.sort((a, b) => a.startedAt.getTime() - b.startedAt.getTime()); return [anchor, ...descendants]; } /** * Lightweight span record containing only the fields needed for timeline rendering. * Excludes heavy fields: input, output, attributes, metadata, tags, links. * This reduces per-span payload from ~17KB to ~370 bytes (~97% reduction). */ const lightSpanRecordSchema = zod_v4.z.object({ ...spanIds, name: spanNameField, spanType: spanTypeField, isEvent: isEventField, startedAt: startedAtField, parentSpanId: parentSpanIdField.nullish(), endedAt: endedAtField.nullish(), error: errorField.nullish(), entityType: require_utils.spanContextFields.entityType, entityId: require_utils.spanContextFields.entityId, entityName: require_utils.spanContextFields.entityName, ...require_utils.dbTimestamps }).describe("Lightweight span record for timeline rendering (excludes input, output, attributes, metadata, tags, links)"); /** * Response schema for getStructure operation. * Returns a trace with lightweight spans (only fields needed for timeline). */ const getStructureResponseSchema = zod_v4.z.object({ traceId: require_utils.traceIdField, spans: zod_v4.z.array(lightSpanRecordSchema) }); /** @deprecated Use {@link getStructureResponseSchema} instead. */ const getTraceLightResponseSchema = getStructureResponseSchema; /** Schema for filtering traces in list queries */ const tracesFilterSchema = zod_v4.z.object({ startedAt: require_utils.dateRangeSchema.optional().describe("Filter by span start time range"), endedAt: require_utils.dateRangeSchema.optional().describe("Filter by span end time range"), spanType: spanTypeField.optional(), traceId: require_utils.traceIdField.optional().describe("Filter by trace ID (matches root span)"), ...sharedFields, status: traceStatusField.optional(), hasChildError: hasChildErrorField.optional() }).describe("Filters for querying traces"); /** * Fields available for ordering trace results */ const tracesOrderByFieldSchema = zod_v4.z.enum(["startedAt", "endedAt"]).describe("Field to order by: 'startedAt' | 'endedAt'"); /** * Order by configuration for trace queries * Follows the existing StorageOrderBy pattern * Defaults to startedAt desc (newest first) */ const tracesOrderBySchema = zod_v4.z.object({ field: tracesOrderByFieldSchema.default("startedAt").describe("Field to order by"), direction: require_utils.sortDirectionSchema.default("DESC").describe("Sort direction") }).describe("Order by configuration"); /** * Arguments for listing traces */ const listTracesArgsSchema = zod_v4.z.object({ mode: require_utils.listModeSchema.optional(), filters: tracesFilterSchema.optional().describe("Optional filters to apply"), pagination: require_utils.paginationArgsSchema.optional(), orderBy: tracesOrderBySchema.optional(), after: require_utils.deltaCursorSchema.optional(), limit: require_utils.deltaLimitSchema }).strict().superRefine(require_utils.refineObservabilityListMode).transform((value) => require_utils.normalizeObservabilityListArgs(value, { orderBy: { field: "startedAt", direction: "DESC" } })).describe("Arguments for listing traces."); /** Schema for listTraces operation response */ const listTracesResponseSchema = zod_v4.z.object({ pagination: require_utils.paginationInfoSchema.optional(), delta: require_utils.deltaInfoSchema.optional(), deltaCursor: require_utils.deltaCursorSchema.optional(), spans: zod_v4.z.array(traceSpanSchema) }); /** Schema for listTracesLight operation response */ const listTracesLightResponseSchema = zod_v4.z.object({ pagination: require_utils.paginationInfoSchema, spans: zod_v4.z.array(lightSpanRecordSchema) }); /** * Span types that anchor a listable trace branch -- the spans a user thinks * about when looking for a specific run (agent/workflow/tool/etc.), * regardless of whether the entity ran as the root of its trace or nested * under a parent. Each row in {@link listBranchesArgsSchema} corresponds to * one such anchor span; the subtree below it is fetched via * {@link getBranchArgsSchema}. * * Excludes sub-operation spans (model_step, workflow_step, scorer_step, * memory_operation, rag_*, etc.) which are internal to a containing branch * rather than separately listable. */ const BRANCH_SPAN_TYPES = [ "agent_run", "workflow_run", "processor_run", "scorer_run", "rag_ingestion", "tool_call", "mcp_tool_call", "provider_tool_call" ]; /** Set form of {@link BRANCH_SPAN_TYPES} for fast membership checks. */ const BRANCH_SPAN_TYPE_SET = new Set(BRANCH_SPAN_TYPES); /** Schema for filtering branch anchor spans in list queries. */ const branchesFilterSchema = zod_v4.z.object({ startedAt: require_utils.dateRangeSchema.optional().describe("Filter by span start time range"), endedAt: require_utils.dateRangeSchema.optional().describe("Filter by span end time range"), spanType: spanTypeField.optional(), traceId: require_utils.traceIdField.optional().describe("Filter by parent trace ID"), ...sharedFields, status: traceStatusField.optional() }).describe("Filters for querying trace branches"); const branchesOrderByFieldSchema = zod_v4.z.enum(["startedAt", "endedAt"]).describe("Field to order by: 'startedAt' | 'endedAt'"); const branchesOrderBySchema = zod_v4.z.object({ field: branchesOrderByFieldSchema.default("startedAt").describe("Field to order by"), direction: require_utils.sortDirectionSchema.default("DESC").describe("Sort direction") }).describe("Order by configuration"); /** * Arguments for listing trace branches. * * Each row is a single branch anchor span ({@link BRANCH_SPAN_TYPES}), * including ones nested under a different root entity. Use this when you * want every run of a given agent/processor/tool regardless of how it was * triggered. Use {@link listTracesArgsSchema} when you want one row per * trace, and {@link getBranchArgsSchema} to expand a single branch into its * subtree. */ const listBranchesArgsSchema = zod_v4.z.object({ mode: require_utils.listModeSchema.optional(), filters: branchesFilterSchema.optional().describe("Optional filters to apply"), pagination: require_utils.paginationArgsSchema.optional(), orderBy: branchesOrderBySchema.optional(), after: require_utils.deltaCursorSchema.optional(), limit: require_utils.deltaLimitSchema }).strict().superRefine(require_utils.refineObservabilityListMode).transform((value) => require_utils.normalizeObservabilityListArgs(value, { orderBy: { field: "startedAt", direction: "DESC" } })).describe("Arguments for listing trace branches."); /** * Schema for listBranches operation response. Each row is a single branch * anchor span -- repeated runs of the same entity within one parent trace * surface as separate rows. */ const listBranchesResponseSchema = zod_v4.z.object({ pagination: require_utils.paginationInfoSchema.optional(), delta: require_utils.deltaInfoSchema.optional(), deltaCursor: require_utils.deltaCursorSchema.optional(), branches: zod_v4.z.array(traceSpanSchema) }); /** * Schema for updating a span (without db timestamps and span IDs) */ const updateSpanRecordSchema = createSpanRecordSchema.omit(omitSpanIds); /** * Schema for updateSpan operation arguments */ const updateSpanArgsSchema = zod_v4.z.object({ spanId: require_utils.spanIdField, traceId: require_utils.traceIdField, updates: updateSpanRecordSchema.partial() }).describe("Arguments for updating a single span"); /** * Schema for batchUpdateSpans operation arguments */ const batchUpdateSpansArgsSchema = zod_v4.z.object({ records: zod_v4.z.array(zod_v4.z.object({ traceId: require_utils.traceIdField, spanId: require_utils.spanIdField, updates: updateSpanRecordSchema.partial() })) }).describe("Arguments for batch updating spans"); /** * Schema for batchDeleteTraces operation arguments */ const batchDeleteTracesArgsSchema = zod_v4.z.object({ traceIds: zod_v4.z.array(require_utils.traceIdField) }).describe("Arguments for batch deleting traces"); /** Schema for listScoresBySpan operation response */ const listScoresBySpanResponseSchema = zod_v4.z.object({ pagination: require_utils.paginationInfoSchema, scores: zod_v4.z.array(scoreRowDataSchema) }); /** Schema for scoreTraces operation request */ const scoreTracesRequestSchema = zod_v4.z.object({ scorerName: zod_v4.z.string().min(1), targets: zod_v4.z.array(zod_v4.z.object({ traceId: require_utils.traceIdField, spanId: require_utils.spanIdField.optional() })).min(1) }); /** Schema for scoreTraces operation response */ const scoreTracesResponseSchema = zod_v4.z.object({ status: zod_v4.z.string(), message: zod_v4.z.string(), traceCount: zod_v4.z.number() }); //#endregion //#region src/storage/constants.ts const TABLE_WORKFLOW_SNAPSHOT = "mastra_workflow_snapshot"; const TABLE_MESSAGES = "mastra_messages"; const TABLE_THREADS = "mastra_threads"; const TABLE_TRACES = "mastra_traces"; const TABLE_RESOURCES = "mastra_resources"; const TABLE_SCORERS = "mastra_scorers"; const TABLE_SPANS = "mastra_ai_spans"; const TABLE_AGENTS = "mastra_agents"; const TABLE_AGENT_VERSIONS = "mastra_agent_versions"; const TABLE_OBSERVATIONAL_MEMORY = "mastra_observational_memory"; const TABLE_PROMPT_BLOCKS = "mastra_prompt_blocks"; const TABLE_PROMPT_BLOCK_VERSIONS = "mastra_prompt_block_versions"; const TABLE_SCORER_DEFINITIONS = "mastra_scorer_definitions"; const TABLE_SCORER_DEFINITION_VERSIONS = "mastra_scorer_definition_versions"; const TABLE_MCP_CLIENTS = "mastra_mcp_clients"; const TABLE_MCP_CLIENT_VERSIONS = "mastra_mcp_client_versions"; const TABLE_MCP_SERVERS = "mastra_mcp_servers"; const TABLE_MCP_SERVER_VERSIONS = "mastra_mcp_server_versions"; const TABLE_WORKSPACES = "mastra_workspaces"; const TABLE_WORKSPACE_VERSIONS = "mastra_workspace_versions"; const TABLE_SKILLS = "mastra_skills"; const TABLE_SKILL_VERSIONS = "mastra_skill_versions"; const TABLE_SKILL_BLOBS = "mastra_skill_blobs"; const TABLE_FAVORITES = "mastra_favorites"; const TABLE_DATASETS = "mastra_datasets"; const TABLE_DATASET_ITEMS = "mastra_dataset_items"; const TABLE_DATASET_VERSIONS = "mastra_dataset_versions"; const TABLE_EXPERIMENTS = "mastra_experiments"; const TABLE_EXPERIMENT_RESULTS = "mastra_experiment_results"; const TABLE_BACKGROUND_TASKS = "mastra_background_tasks"; const TABLE_SCHEDULES = "mastra_schedules"; const TABLE_SCHEDULE_TRIGGERS = "mastra_schedule_triggers"; const TABLE_WORKFLOW_DEFINITIONS = "mastra_workflow_definitions"; const TABLE_CHANNEL_INSTALLATIONS = "mastra_channel_installations"; const TABLE_CHANNEL_CONFIG = "mastra_channel_config"; const TABLE_TOOL_PROVIDER_CONNECTIONS = "mastra_tool_provider_connections"; const TABLE_NOTIFICATIONS = "mastra_notifications"; const TABLE_HARNESS_SESSIONS = "mastra_harness_sessions"; const TABLE_THREAD_STATE = "mastra_thread_state"; const SCORERS_SCHEMA = { id: { type: "text", nullable: false, primaryKey: true }, scorerId: { type: "text" }, traceId: { type: "text", nullable: true }, spanId: { type: "text", nullable: true }, runId: { type: "text" }, scorer: { type: "jsonb" }, preprocessStepResult: { type: "jsonb", nullable: true }, extractStepResult: { type: "jsonb", nullable: true }, analyzeStepResult: { type: "jsonb", nullable: true }, score: { type: "float" }, reason: { type: "text", nullable: true }, metadata: { type: "jsonb", nullable: true }, preprocessPrompt: { type: "text", nullable: true }, extractPrompt: { type: "text", nullable: true }, generateScorePrompt: { type: "text", nullable: true }, generateReasonPrompt: { type: "text", nullable: true }, analyzePrompt: { type: "text", nullable: true }, reasonPrompt: { type: "text", nullable: true }, input: { type: "jsonb" }, output: { type: "jsonb" }, additionalContext: { type: "jsonb", nullable: true }, requestContext: { type: "jsonb", nullable: true }, /** * Things you can evaluate */ entityType: { type: "text", nullable: true }, entity: { type: "jsonb", nullable: true }, entityId: { type: "text", nullable: true }, source: { type: "text" }, resourceId: { type: "text", nullable: true }, threadId: { type: "text", nullable: true }, organizationId: { type: "text", nullable: true }, projectId: { type: "text", nullable: true }, batchId: { type: "text", nullable: true }, datasetId: { type: "text", nullable: true }, datasetItemId: { type: "text", nullable: true }, createdAt: { type: "timestamp" }, updatedAt: { type: "timestamp" } }; const SPAN_SCHEMA = buildStorageSchema(spanRecordSchema); /** * @deprecated Use SPAN_SCHEMA instead. This legacy schema is retained only for migration purposes. * @internal */ const OLD_SPAN_SCHEMA = { traceId: { type: "text", nullable: false }, spanId: { type: "text", nullable: false }, parentSpanId: { type: "text", nullable: true }, name: { type: "text", nullable: false }, scope: { type: "jsonb", nullable: true }, spanType: { type: "text", nullable: false }, attributes: { type: "jsonb", nullable: true }, metadata: { type: "jsonb", nullable: true }, links: { type: "jsonb", nullable: true }, input: { type: "jsonb", nullable: true }, output: { type: "jsonb", nullable: true }, error: { type: "jsonb", nullable: true }, startedAt: { type: "timestamp", nullable: false }, endedAt: { type: "timestamp", nullable: true }, createdAt: { type: "timestamp", nullable: false }, updatedAt: { type: "timestamp", nullable: true }, isEvent: { type: "boolean", nullable: false } }; const AGENTS_SCHEMA = { id: { type: "text", nullable: false, primaryKey: true }, status: { type: "text", nullable: false }, activeVersionId: { type: "text", nullable: true }, authorId: { type: "text", nullable: true }, visibility: { type: "text", nullable: true }, metadata: { type: "jsonb", nullable: true }, favoriteCount: { type: "integer", nullable: true }, createdAt: { type: "timestamp", nullable: false }, updatedAt: { type: "timestamp", nullable: false } }; const AGENT_VERSIONS_SCHEMA = { id: { type: "text", nullable: false, primaryKey: true }, agentId: { type: "text", nullable: false }, versionNumber: { type: "integer", nullable: false }, name: { type: "text", nullable: false }, description: { type: "text", nullable: true }, instructions: { type: "text", nullable: false }, model: { type: "jsonb", nullable: false }, tools: { type: "jsonb", nullable: true }, defaultOptions: { type: "jsonb", nullable: true }, workflows: { type: "jsonb", nullable: true }, agents: { type: "jsonb", nullable: true }, integrationTools: { type: "jsonb", nullable: true }, toolProviders: { type: "jsonb", nullable: true }, inputProcessors: { type: "jsonb", nullable: true }, outputProcessors: { type: "jsonb", nullable: true }, memory: { type: "jsonb", nullable: true }, scorers: { type: "jsonb", nullable: true }, mcpClients: { type: "jsonb", nullable: true }, requestContextSchema: { type: "jsonb", nullable: true }, workspace: { type: "jsonb", nullable: true }, skills: { type: "jsonb", nullable: true }, skillsFormat: { type: "text", nullable: true }, browser: { type: "jsonb", nullable: true }, changedFields: { type: "jsonb", nullable: true }, changeMessage: { type: "text", nullable: true }, createdAt: { type: "timestamp", nullable: false } }; const PROMPT_BLOCKS_SCHEMA = { id: { type: "text", nullable: false, primaryKey: true }, status: { type: "text", nullable: false }, activeVersionId: { type: "text", nullable: true }, authorId: { type: "text", nullable: true }, metadata: { type: "jsonb", nullable: true }, createdAt: { type: "timestamp", nullable: false }, updatedAt: { type: "timestamp", nullable: false } }; const PROMPT_BLOCK_VERSIONS_SCHEMA = { id: { type: "text", nullable: false, primaryKey: true }, blockId: { type: "text", nullable: false }, versionNumber: { type: "integer", nullable: false }, name: { type: "text", nullable: false }, description: { type: "text", nullable: true }, content: { type: "text", nullable: false }, rules: { type: "jsonb", nullable: true }, requestContextSchema: { type: "jsonb", nullable: true }, changedFields: { type: "jsonb", nullable: true }, changeMessage: { type: "text", nullable: true }, createdAt: { type: "timestamp", nullable: false } }; const SCORER_DEFINITIONS_SCHEMA = { id: { type: "text", nullable: false, primaryKey: true }, status: { type: "text", nullable: false }, activeVersionId: { type: "text", nullable: true }, authorId: { type: "text", nullable: true }, organizationId: { type: "text", nullable: true }, projectId: { type: "text", nullable: true }, metadata: { type: "jsonb", nullable: true }, createdAt: { type: "timestamp", nullable: false }, updatedAt: { type: "timestamp", nullable: false } }; const SCORER_DEFINITION_VERSIONS_SCHEMA = { id: { type: "text", nullable: false, primaryKey: true }, scorerDefinitionId: { type: "text", nullable: false }, versionNumber: { type: "integer", nullable: false }, name: { type: "text", nullable: false }, description: { type: "text", nullable: true }, type: { type: "text", nullable: false }, model: { type: "jsonb", nullable: true }, instructions: { type: "text", nullable: true }, scoreRange: { type: "jsonb", nullable: true }, presetConfig: { type: "jsonb", nullable: true }, defaultSampling: { type: "jsonb", nullable: true }, changedFields: { type: "jsonb", nullable: true }, changeMessage: { type: "text", nullable: true }, createdAt: { type: "timestamp", nullable: false } }; const MCP_CLIENTS_SCHEMA = { id: { type: "text", nullable: false, primaryKey: true }, status: { type: "text", nullable: false }, activeVersionId: { type: "text", nullable: true }, authorId: { type: "text", nullable: true }, metadata: { type: "jsonb", nullable: true }, createdAt: { type: "timestamp", nullable: false }, updatedAt: { type: "timestamp", nullable: false } }; const MCP_CLIENT_VERSIONS_SCHEMA = { id: { type: "text", nullable: false, primaryKey: true }, mcpClientId: { type: "text", nullable: false }, versionNumber: { type: "integer", nullable: false }, name: { type: "text", nullable: false }, description: { type: "text", nullable: true }, servers: { type: "jsonb", nullable: false }, changedFields: { type: "jsonb", nullable: true }, changeMessage: { type: "text", nullable: true }, createdAt: { type: "timestamp", nullable: false } }; const MCP_SERVERS_SCHEMA = { id: { type: "text", nullable: false, primaryKey: true }, status: { type: "text", nullable: false }, activeVersionId: { type: "text", nullable: true }, authorId: { type: "text", nullable: true }, metadata: { type: "jsonb", nullable: true }, createdAt: { type: "timestamp", nullable: false }, updatedAt: { type: "timestamp", nullable: false } }; const MCP_SERVER_VERSIONS_SCHEMA = { id: { type: "text", nullable: false, primaryKey: true }, mcpServerId: { type: "text", nullable: false }, versionNumber: { type: "integer", nullable: false }, name: { type: "text", nullable: false }, version: { type: "text", nullable: false }, description: { type: "text", nullable: true }, instructions: { type: "text", nullable: true }, repository: { type: "jsonb", nullable: true }, releaseDate: { type: "text", nullable: true }, isLatest: { type: "boolean", nullable: true }, packageCanonical: { type: "text", nullable: true }, tools: { type: "jsonb", nullable: true }, agents: { type: "jsonb", nullable: true }, workflows: { type: "jsonb", nullable: true }, changedFields: { type: "jsonb", nullable: true }, changeMessage: { type: "text", nullable: true }, createdAt: { type: "timestamp", nullable: false } }; const WORKFLOW_DEFINITIONS_SCHEMA = { id: { type: "text", nullable: false, primaryKey: true }, description: { type: "text", nullable: true }, metadata: { type: "jsonb", nullable: true }, inputSchema: { type: "jsonb", nullable: false }, outputSchema: { type: "jsonb", nullable: false }, stateSchema: { type: "jsonb", nullable: true }, requestContextSchema: { type: "jsonb", nullable: true }, graph: { type: "jsonb", nullable: false }, status: { type: "text", nullable: false }, source: { type: "text", nullable: false }, authorId: { type: "text", nullable: true }, createdAt: { type: "timestamp", nullable: false }, updatedAt: { type: "timestamp", nullable: false } }; const WORKSPACES_SCHEMA = { id: { type: "text", nullable: false, primaryKey: true }, status: { type: "text", nullable: false }, activeVersionId: { type: "text", nullable: true }, authorId: { type: "text", nullable: true }, metadata: { type: "jsonb", nullable: true }, createdAt: { type: "timestamp", nullable: false }, updatedAt: { type: "timestamp", nullable: false } }; const WORKSPACE_VERSIONS_SCHEMA = { id: { type: "text", nullable: false, primaryKey: true }, workspaceId: { type: "text", nullable: false }, versionNumber: { type: "integer", nullable: false }, name: { type: "text", nullable: false }, description: { type: "text", nullable: true }, filesystem: { type: "jsonb", nullable: true }, sandbox: { type: "jsonb", nullable: true }, mounts: { type: "jsonb", nullable: true }, search: { type: "jsonb", nullable: true }, skills: { type: "jsonb", nullable: true }, tools: { type: "jsonb", nullable: true }, autoSync: { type: "boolean", nullable: true }, operationTimeout: { type: "integer", nullable: true }, changedFields: { type: "jsonb", nullable: true }, changeMessage: { type: "text", nullable: true }, createdAt: { type: "timestamp", nullable: false } }; const SKILLS_SCHEMA = { id: { type: "text", nullable: false, primaryKey: true }, status: { type: "text", nullable: false }, activeVersionId: { type: "text", nullable: true }, authorId: { type: "text", nullable: true }, visibility: { type: "text", nullable: true }, favoriteCount: { type: "integer", nullable: true }, createdAt: { type: "timestamp", nullable: false }, updatedAt: { type: "timestamp", nullable: false } }; const FAVORITES_SCHEMA = { userId: { type: "text", nullable: false }, entityType: { type: "text", nullable: false }, entityId: { type: "text", nullable: false }, createdAt: { type: "timestamp", nullable: false } }; /** * Per-author registry of authorized tool provider connections. Stores a stable * user-supplied label across agents. Composite primary key on * (authorId, providerId, connectionId). `scope` buckets identity: * 'per-author' (default), 'shared' (visible to all callers), or * 'caller-supplied' (authorId is a host-app end-user id forwarded via request * context). */ const TOOL_PROVIDER_CONNECTIONS_SCHEMA = { authorId: { type: "text", nullable: false }, providerId: { type: "text", nullable: false }, connectionId: { type: "text", nullable: false }, toolkit: { type: "text", nullable: false }, label: { type: "text", nullable: true }, scope: { type: "text", nullable: false }, createdAt: { type: "timestamp", nullable: false }, updatedAt: { type: "timestamp", nullabl