Feedback
Added in: @mastra/core@1.18.0
Feedback APIs store and query human-in-the-loop observability signals such as ratings, thumbs, comments, and corrections. Use the feedback guide for usage patterns.
Usage exampleUsage example的直接链接
The following example records a rating for a persisted trace through the observability entrypoint. addFeedback() is optional on the entrypoint, so check that the active observability implementation supports it before calling it.
if (!mastra.observability.addFeedback) {
throw new Error('Feedback is not supported by the active observability implementation')
}
await mastra.observability.addFeedback({
traceId: 'trace-123',
spanId: 'span-456',
feedback: {
feedbackSource: 'user',
feedbackType: 'rating',
value: 1,
comment: 'Helpful answer.',
},
})
Create feedbackCreate feedback的直接链接
addFeedback(args)addfeedbackargs的直接链接
Adds feedback to a persisted trace or span through the observability entrypoint.
await mastra.observability.addFeedback?.({
traceId: 'trace-123',
spanId: 'span-456',
feedback: {
feedbackSource: 'user',
feedbackType: 'rating',
value: 1,
comment: 'Helpful answer.',
},
})
traceId?:
spanId?:
correlationContext?:
feedback:
Without correlationContext, the method looks up traceId in configured observability storage. If the trace or requested span isn't found, Mastra logs a warning and drops the feedback event. Configure MastraStorageExporter when adding feedback by ID after execution, including when MastraPlatformExporter handles remote export.
createFeedback(args)createfeedbackargs的直接链接
Creates one feedback record through the observability storage domain. Storage-level calls write directly to the store, so include timestamp.
await observability.createFeedback({
feedback: {
feedbackId: 'feedback-1',
timestamp: new Date(),
traceId: 'trace-123',
spanId: 'span-456',
feedbackSource: 'user',
feedbackType: 'rating',
value: 1,
comment: 'Helpful answer.',
},
})
The HTTP and client SDK create route accepts CreateFeedbackBody and sets timestamp server-side. It generates feedbackId when omitted:
await mastraClient.createFeedback({
feedback: {
traceId: 'trace-123',
spanId: 'span-456',
feedbackSource: 'user',
feedbackType: 'rating',
value: 1,
},
})
batchCreateFeedback(args)batchcreatefeedbackargs的直接链接
Creates multiple feedback records through the observability storage domain. This method isn't exposed by the HTTP routes or @mastra/client-js.
await observability.batchCreateFeedback({
feedbacks: [
{
feedbackId: 'feedback-1',
timestamp: new Date(),
traceId: 'trace-123',
feedbackSource: 'user',
feedbackType: 'rating',
value: 1,
},
{
feedbackId: 'feedback-2',
timestamp: new Date(),
traceId: 'trace-123',
feedbackSource: 'qa',
feedbackType: 'comment',
value: 'Needs a citation before shipping.',
},
],
})
Delete feedbackDelete feedback的直接链接
deleteFeedback(args)deletefeedbackargs的直接链接
Deletes up to 1,000 feedback records by id. The operation is idempotent: ids that don't exist are ignored, and an empty feedbackIds array is a no-op. When organizationId or resourceId is provided, only records matching that scope are deleted.
await mastraClient.deleteFeedback({
feedbackIds: ['feedback-1', 'feedback-2'],
})
feedbackIds:
organizationId?:
resourceId?:
Returns Promise<{ success: boolean }> from mastraClient.deleteFeedback() and the HTTP route. The storage domain method returns Promise<void>. Requests with more than 1,000 ids return 400, and a server running @mastra/core older than 1.66.0 returns 501. ClickHouse vNext, PostgreSQL vNext, DuckDB, and the in-memory store implement deletion. Every other adapter, including LibSQL and MongoDB, throws OBSERVABILITY_STORAGE_DELETE_FEEDBACK_NOT_IMPLEMENTED.
On ClickHouse, deletion uses lightweight deletes on the main feedback events table to remove rows from reads, including OLAP queries, without guaranteeing immediate physical removal, so open-source deployments must configure an observability retention period to physically purge them. Each request is marked applied once its delete succeeds; if the delete fails, the request stays unapplied, doesn't block updateFeedbackReviewStatus() on the still-visible feedback, and you retry by calling deleteFeedback() again. updateFeedbackReviewStatus() also retries the delete and throws a not-found error if the retry succeeds, or saves the new status and throws the delete's error if it fails again. Open-source deployments have no background reconciler. ClickHouse applies a TTL to deletion requests only when all five signals have finite retention. See ClickHouse native TTL. Delete APIs leave the separate delta cursor table untouched. Its rows contain identifiers rather than feedback payloads and expire within two days.
deleteScores(args)deletescoresargs的直接链接
Deletes up to 1,000 score records by id. It behaves like deleteFeedback() with scoreIds in place of feedbackIds, and Oracle Database also implements it. Unsupported adapters throw OBSERVABILITY_STORAGE_DELETE_SCORES_NOT_IMPLEMENTED.
await mastraClient.deleteScores({
scoreIds: ['score-1', 'score-2'],
})
List feedbackList feedback的直接链接
listFeedback(args?)listfeedbackargs的直接链接
Returns feedback records in page mode or delta mode.
const response = await mastraClient.listFeedback({
filters: {
feedbackType: 'rating',
feedbackSource: 'studio',
},
pagination: { page: 0, perPage: 20 },
orderBy: { field: 'timestamp', direction: 'DESC' },
})
mode?:
filters?:
pagination?:
page is zero-indexed.orderBy?:
after?:
limit?:
OLAP queriesOLAP queries的直接链接
OLAP feedback queries operate on numeric value fields.
getFeedbackAggregate(args)getfeedbackaggregateargs的直接链接
Returns one aggregate feedback value.
const response = await mastraClient.getFeedbackAggregate({
feedbackType: 'rating',
feedbackSource: 'user',
aggregation: 'avg',
comparePeriod: 'previous_day',
})
feedbackType:
feedbackSource?:
aggregation:
filters?:
comparePeriod?:
getFeedbackBreakdown(args)getfeedbackbreakdownargs的直接链接
Returns feedback values grouped by dimensions.
const response = await mastraClient.getFeedbackBreakdown({
feedbackType: 'rating',
groupBy: ['entityName'],
aggregation: 'avg',
})
getFeedbackTimeSeries(args)getfeedbacktimeseriesargs的直接链接
Returns feedback values bucketed by interval.
const response = await mastraClient.getFeedbackTimeSeries({
feedbackType: 'rating',
interval: '1h',
aggregation: 'avg',
groupBy: ['feedbackSource'],
})
getFeedbackPercentiles(args)getfeedbackpercentilesargs的直接链接
Returns percentile values bucketed by interval.
const response = await mastraClient.getFeedbackPercentiles({
feedbackType: 'rating',
percentiles: [0.5, 0.95],
interval: '1d',
})
TypesTypes的直接链接
FeedbackRecordfeedbackrecord的直接链接
feedbackId?:
timestamp:
traceId?:
spanId?:
feedbackSource?:
source?:
feedbackSource.feedbackType:
value:
comment?:
feedbackUserId?:
sourceId?:
metadata?:
Shared context fieldsShared context fields的直接链接
Feedback records can include shared observability context fields for filtering, grouping, and correlation with traces, logs, metrics, and scores.
entityType?:
entityId?:
entityName?:
parentEntityType?:
parentEntityId?:
parentEntityName?:
rootEntityType?:
rootEntityId?:
rootEntityName?:
userId?:
organizationId?:
resourceId?:
runId?:
sessionId?:
threadId?:
requestId?:
environment?:
serviceName?:
scope?:
entityVersionId?:
parentEntityVersionId?:
rootEntityVersionId?:
experimentId?:
executionSource?:
FeedbackInputfeedbackinput的直接链接
Use FeedbackInput with mastra.observability.addFeedback(), recordedTrace.addFeedback(), and recordedSpan.addFeedback().
feedbackSource?:
source?:
feedbackSource.feedbackType:
value:
comment?:
feedbackUserId?:
userId?:
feedbackUserId.metadata?:
experimentId?:
correlationContext.experimentId on the exported event instead.sourceId?:
FeedbackFilterfeedbackfilter的直接链接
Use FeedbackFilter in listFeedback() and OLAP query filters.
timestamp?:
traceId?:
spanId?:
feedbackType?:
feedbackSource?:
source?:
feedbackSource.feedbackUserId?:
reviewStatus?:
entityType?:
entityName?:
entityVersionId?:
parentEntityType?:
parentEntityName?:
parentEntityVersionId?:
rootEntityType?:
rootEntityName?:
rootEntityVersionId?:
userId?:
organizationId?:
resourceId?:
runId?:
sessionId?:
threadId?:
requestId?:
serviceName?:
environment?:
executionSource?:
experimentId?:
HTTP routesHTTP routes的直接链接
These routes belong to a Mastra runtime and use its configured observability storage. They're separate from the unversioned Mastra Platform Feedback API, which doesn't provide a feedback creation route.
| Method | Path | Purpose | Permission |
|---|---|---|---|
GET | /api/observability/feedback | List feedback records | observability:read |
POST | /api/observability/feedback | Create a feedback record | observability:write |
DELETE | /api/observability/feedback | Delete feedback records by id | observability:delete |
DELETE | /api/observability/scores | Delete score records by id | observability:delete |
PATCH | /api/observability/feedback/:feedbackId/review-status | Update review status | observability:write |
POST | /api/observability/feedback/aggregate | Return one aggregate value | observability:read |
POST | /api/observability/feedback/breakdown | Group feedback by dimensions | observability:read |
POST | /api/observability/feedback/timeseries | Bucket feedback by interval | observability:read |
POST | /api/observability/feedback/percentiles | Return percentile series | observability:read |
List query parametersList query parameters的直接链接
GET /api/observability/feedback takes its arguments as URL query parameters. The Mastra Platform Feedback API accepts the same parameters on its GET /feedback endpoint.
curl -sS "http://localhost:4111/api/observability/feedback?traceId=trace-123&environment=production&feedbackType=rating&page=0&perPage=20"
Every field of FeedbackFilter is accepted as a top-level query parameter with the same name, for example traceId, spanId, feedbackType, feedbackSource, feedbackUserId, reviewStatus, entityName, environment, experimentId, or tags. Repeat a parameter to pass multiple values where the filter accepts an array, such as feedbackType=rating&feedbackType=thumbs. Pass object-valued filters such as timestamp as JSON, for example timestamp={"start":"2026-01-01T00:00:00Z"} URL-encoded.
The remaining parameters control paging and delta polling:
mode?:
page?:
perPage?:
field?:
direction?:
after?:
limit?:
Requests that mix modes return 400, for example page or perPage with mode=delta, or after or limit without it. The analytics routes take the same JSON bodies as getFeedbackAggregate(), getFeedbackBreakdown(), getFeedbackTimeSeries(), and getFeedbackPercentiles().