Co-authored-by: Tianyi Cui <53024+tianyicui@users.noreply.github.com>
description, kind
| description | kind |
|---|---|
| Per-message feedback for the Web GUI: the Like/Dislike pair and optional note in the finalized assistant message's action row; for users and maintainers of the feedback experience. | package-reference |
@deepseek-ai/dsh-client-ui-message-feedback
English | 中文
Summary
This package adds per-message feedback to the Web GUI: a Like/Dislike pair plus an optional note, contributed as the feedback entry of the finalized assistant message's action strip. It renders on the closing assistant message of each turn — earlier steps of a multi-step turn produce tool rows rather than a rateable body. One controller per Session backs every message control in that Session, so a single list read seeds the whole transcript. Ratings and notes are log-only Session events: they never enter model context. Deletion retracts the current item without erasing its earlier log entries.
Table of Contents
- Use this package
- Understand the implementation
- Further Exploration
- Model Experience
- Known Limitations and Deferred Work
- Dev Note
Use this package
Mount this plugin alongside ui-conversation; the Like/Dislike pair then appears in the action row of each turn's closing assistant message, between copy and branch. Clicking the recorded rating retracts the feedback; switching sides carries the existing note forward. The note editor is a dialog popover anchored under its trigger, so the row keeps its single line whether the editor is open or closed.
Failures
A rating or list-load failure shows inline in the row; a note-save failure shows inside the popover, which stays open so the draft can be corrected. Only finalized messages reach the slot — an interruption-frozen partial carries no messageId and therefore no feedback controls.
Understand the implementation
Implementation internals — click to expand
The package contributes the feedback entry (order 10) of conversation.chat.assistant-actions, declared by ui-conversation and rendered inside the finalized assistant message's IconActions row. One MessageFeedbackController per Session backs every message control in that Session, so a single messageFeedback.list read seeds the whole transcript; the read is deferred to the first hover or focus rather than fired on mount. Mutations go through ctx.remote.messageFeedback; the Host owns per-item compare-and-set. Every put and delete carries the version this controller last observed, and a version-conflict reply carries the authoritative item, so a lost race reconciles from the reply itself instead of refetching. Mutations serialize per Session, so a queued operation always compares against the committed version.
Further Exploration
Read these pages when the feedback surface is not enough. They move from the browser strip to the Session-log backend and the conversation shell.
- dsh-message-feedback — the Session-log backend that owns per-item compare-and-set and persistence.
- ui-conversation — declares the assistant-actions strip and renders the action row.
- Client package map — adjacent browser UI packages.
Model Experience
None, as ratings and notes are log-only events, not model input. Optional Session-log delivery uses request metadata rather than model context.
KV Cache effect
None; feedback mutations leave the model-visible history unchanged.
Known Limitations and Deferred Work
These limits define the current feedback surface. They are current package constraints, not a general rating comparison or a task backlog.
- Note size is a Host policy — the deployment configures
maxNoteBytes(8192 in the Web bundle) and the Host rejects an oversized note withnote-too-large. The editor does not pre-check the limit, so an oversized note fails on save rather than while typing. - No cross-tab push — a second tab's rating becomes visible on reconnect or on the next conflict reply, not immediately; the controller does not consume feedback log events.
- Chat view only — the trajectory and waterfall views render no feedback controls even though their assistant nodes carry the same
messageId.
Dev Note
Working context for maintainers — click to expand
None.
Runtime invariant: No companion is published. The plugin owns one slot registration and one per-session controller map, both released by the same effect disposer. The lifecycle spec proves the registration is withdrawn and every controller is dropped when the owning fiber is disposed, so no second authority exists to check at runtime.