feedback(traceId, {...})
Rating the answer itself: 👍 / 👎, an optional comment, or a before → after correction. This is the existing end-user feedback endpoint, exposed here for your app to forward.
- A
dislikepromotes into a confirmed human signal on that trace. - A
likeretracts any pending signals attributed to that trace.
traces.feedback — same call, spec-canonical name.
rating(required) —"like"or"dislike".comment— free-text note; surfaces on the trace and in cluster review.correction—{ before, after }pair. Theafteris what the user says the answer should have been. Fed into the improvement loop as candidate fix content.
signals.report(traceId, {...})
An external outcome the answer-quality detectors can’t see: refunded, reopened, escalated to human, resolved. These land as candidate signals with origin=sdk_report and go through the same cluster / dataset path as detected signals.
outcome(required) — free-form string. Common vocab:resolved,reopened,escalated,refunded,abandoned. Pick a set and stick to it — it’s how your clusters group.reason— free-text note.
Why keep the two separate
Mixingfeedback and signals.report makes detectors and clusters noisy:
feedbackspeaks to whether the answer was right. It weighs into answer-quality metrics.signals.reportspeaks to what actually happened downstream. It weighs into outcome metrics and can surface failures the answer-quality detectors miss.
feedback) but the user still churns (escalated signal). Both should land, on different tracks.
Where the traceId comes from
- From
flows.run—r.traceIdon the return value. Preferred: you have it inline. - From your own logs — if you captured
traceIdearlier and are now posting feedback on it, that also works. - Correlation with
newTraceRef— for pre-run correlation across your own logs.
MCP / CLI equivalents
The MCP tool and CLI surface the same operation:nora feedback for the full CLI shape.