fix(feedback): address review findings in the controller and controls
Resolve the note-erasure race the review found: a control that rendered before the first list read held no item and passed note=undefined, so switching a rating silently dropped the stored note. The controller now owns note resolution and toggle-vs-retract, deciding from the committed item inside the serialized mutation, and clearNote expresses deletion. Also from review: - serialize the reconnect re-read behind queued mutations (resync), so a list reply cannot resurrect a version a newer mutation replaced - re-check disposal after the seeding read, so an unloaded fiber never reaches the wire - drop Object.freeze on Maps, which does not prevent set/delete - declare the @deepseek-ai/dsh-client-connection dependency it imports - surface a failed list load in the controls - drop the /client value exports that had no consumer - state the per-turn render scope in the README and subsystem pages - align the package version with the root
This commit is contained in:
@@ -205,7 +205,7 @@ Plugin disposal closes mutation admission, drains accepted per-Session queue wor
|
||||
|
||||
[`@deepseek-ai/dsh-client-ui-feedback`](../../packages/client/ui-feedback) is the browser consumer. `@deepseek-ai/dsh-api-remotes` mounts the generated `messageFeedback` contribution, so the plugin calls `ctx.remote.messageFeedback` and never touches the transport.
|
||||
|
||||
The controls are the `feedback` entry (order 10) of the `conversation.chat.assistant-actions` list slot, which `ui-conversation` declares and renders inside the finalized assistant message's IconActions row. Reaching that render site required one plumbing change: `AssistantMessageNode` now carries the optional `messageId` from the `assistant/message` event. The field is absent on interruption-frozen partials, and the render site skips the slot when it is absent, so only messages the Host accepts as feedback targets present controls.
|
||||
The controls are the `feedback` entry (order 10) of the `conversation.chat.assistant-actions` list slot, which `ui-conversation` declares and renders inside the finalized assistant message's IconActions row. Reaching that render site required one plumbing change: `AssistantMessageNode` now carries the optional `messageId` from the `assistant/message` event. The field is absent on interruption-frozen partials, and the render site skips the slot when it is absent. The strip renders once per turn, on the closing assistant message: the Host accepts every append-origin step message as a target, but earlier steps of a multi-step turn render tool rows rather than a rateable body, so the UI exposes a narrower set than the Host contract allows.
|
||||
|
||||
One `FeedbackController` per Session backs every message control in that Session: a single `list` read seeds the whole transcript, deferred to first hover or focus rather than fired on mount. Each mutation sends the version that controller last observed as `ifVersion`; a `version-conflict` reply carries the authoritative item, so the controller reconciles from the reply instead of refetching. Mutations serialize per Session so a queued operation compares against the committed version. A `connection/reset` refreshes only Sessions already read.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user