@deepseek-ai/dsh-client-ui-message-feedback 0.1.1-rc.2 → 0.1.2-alpha.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.i18n.yaml +2 -2
- package/README.md +67 -5
- package/README.zh.md +70 -8
- package/lib/client.js +30 -58
- package/lib/types/client/controller.d.ts +8 -31
- package/lib/types/client/index.d.ts +2 -2
- package/lib/types/client/slots.d.ts +1 -1
- package/package.json +19 -24
package/README.i18n.yaml
CHANGED
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
|
3
3
|
# after editing either side, bring the other along and re-record with:
|
|
4
4
|
# pnpm run verify-translation-pairing --write packages/client/ui-message-feedback/README.md
|
|
5
|
-
README.md:
|
|
6
|
-
README.zh.md:
|
|
5
|
+
README.md: 2610d0d362438977512ce753eecb66cb77497812
|
|
6
|
+
README.zh.md: 58e4dc10d8d42c14cb711261b401d9cf3bec8f98
|
package/README.md
CHANGED
|
@@ -1,15 +1,62 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "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."
|
|
3
|
+
kind: "package-reference"
|
|
4
|
+
---
|
|
5
|
+
|
|
1
6
|
# @deepseek-ai/dsh-client-ui-message-feedback
|
|
2
7
|
|
|
3
8
|
English | [中文](README.zh.md)
|
|
4
9
|
|
|
5
|
-
|
|
10
|
+
## Summary
|
|
11
|
+
|
|
12
|
+
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. Feedback is a sidecar: ratings and notes never enter the session log, the model context, or telemetry.
|
|
13
|
+
|
|
14
|
+
## Table of Contents
|
|
15
|
+
|
|
16
|
+
- [Use this package](#use-this-package)
|
|
17
|
+
- [Understand the implementation](#understand-the-implementation)
|
|
18
|
+
- [Further Exploration](#further-exploration)
|
|
19
|
+
- [Model Experience](#model-experience)
|
|
20
|
+
- [Known Limitations and Deferred Work](#known-limitations-and-deferred-work)
|
|
21
|
+
- [Dev Note](#dev-note)
|
|
22
|
+
|
|
23
|
+
-----
|
|
24
|
+
|
|
25
|
+
<a id="use-this-package"></a>
|
|
26
|
+
## Use this package
|
|
27
|
+
|
|
28
|
+
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.
|
|
29
|
+
|
|
30
|
+
### Failures
|
|
31
|
+
|
|
32
|
+
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.
|
|
33
|
+
|
|
34
|
+
-----
|
|
35
|
+
|
|
36
|
+
<a id="understand-the-implementation"></a>
|
|
37
|
+
## Understand the implementation
|
|
38
|
+
|
|
39
|
+
<details>
|
|
40
|
+
<summary>Implementation internals — click to expand</summary>
|
|
6
41
|
|
|
7
|
-
One `MessageFeedbackController` per Session backs every message control in that Session, so a single `messageFeedback.list` read seeds the whole transcript
|
|
42
|
+
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.
|
|
8
43
|
|
|
9
|
-
|
|
44
|
+
</details>
|
|
10
45
|
|
|
11
|
-
|
|
46
|
+
-----
|
|
12
47
|
|
|
48
|
+
<a id="further-exploration"></a>
|
|
49
|
+
## Further Exploration
|
|
50
|
+
|
|
51
|
+
Read these pages when the feedback surface is not enough. They move from the browser strip to the sidecar backend and the conversation shell.
|
|
52
|
+
|
|
53
|
+
- [dsh-message-feedback](../../feedback/message-feedback/README.md) — the sidecar backend that owns per-item compare-and-set.
|
|
54
|
+
- [ui-conversation](../ui-conversation/README.md) — declares the assistant-actions strip and renders the action row.
|
|
55
|
+
- [Client package map](../README.md) — adjacent browser UI packages.
|
|
56
|
+
|
|
57
|
+
-----
|
|
58
|
+
|
|
59
|
+
<a id="model-experience"></a>
|
|
13
60
|
## Model Experience
|
|
14
61
|
|
|
15
62
|
None, as feedback is a sidecar that never enters the append-only Session log, the model context, or telemetry; no rating or note is ever visible to the model.
|
|
@@ -20,6 +67,21 @@ None; no feedback mutation touches the history tail.
|
|
|
20
67
|
|
|
21
68
|
## Known Limitations and Deferred Work
|
|
22
69
|
|
|
70
|
+
<a id="known-limitations-and-deferred-work"></a>
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
These limits define the current feedback surface. They are current package constraints, not a general rating comparison or a task backlog.
|
|
74
|
+
|
|
23
75
|
- **Note size is a Host policy** — the deployment configures `maxNoteBytes` (8192 in the Web bundle) and the Host rejects an oversized note with `note-too-large`. The editor does not pre-check the limit, so an oversized note fails on save rather than while typing.
|
|
24
76
|
- **No cross-tab push** — a second tab's rating becomes visible on reconnect or on the next conflict reply, not immediately; the sidecar publishes no live frames.
|
|
25
|
-
- **Chat view only** — the trajectory and waterfall views render no feedback controls even though their assistant nodes
|
|
77
|
+
- **Chat view only** — the trajectory and waterfall views render no feedback controls even though their assistant nodes carry the same `messageId`.
|
|
78
|
+
|
|
79
|
+
<a id="dev-note"></a>
|
|
80
|
+
### Dev Note
|
|
81
|
+
|
|
82
|
+
<details>
|
|
83
|
+
<summary>Working context for maintainers — click to expand</summary>
|
|
84
|
+
|
|
85
|
+
None.
|
|
86
|
+
|
|
87
|
+
</details>
|
package/README.zh.md
CHANGED
|
@@ -1,15 +1,62 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Web GUI 的逐消息反馈:已定稿助手消息动作行中的 Like/Dislike 对与可选备注;供反馈体验的用户与维护者阅读。"
|
|
3
|
+
kind: "package-reference"
|
|
4
|
+
---
|
|
5
|
+
|
|
1
6
|
# @deepseek-ai/dsh-client-ui-message-feedback
|
|
2
7
|
|
|
3
8
|
[English](README.md) | 中文
|
|
4
9
|
|
|
5
|
-
|
|
10
|
+
## 概述
|
|
11
|
+
|
|
12
|
+
本包为 Web GUI 增加逐消息反馈:一对 Like/Dislike 按钮加一个可选备注,作为已定稿助手消息动作条的 `feedback` 条目贡献。它渲染在每个轮次的收尾助手消息上——多步骤轮次中较早的步骤产出工具行而非可评分正文。每个 Session 一个控制器支撑该 Session 内所有消息的控件,因此一次列表读取即可填充整段对话。反馈是 sidecar:评分与备注绝不进入会话日志、模型上下文或遥测。
|
|
13
|
+
|
|
14
|
+
## 目录
|
|
15
|
+
|
|
16
|
+
- [使用本包](#use-this-package)
|
|
17
|
+
- [理解实现](#understand-the-implementation)
|
|
18
|
+
- [进一步探索](#further-exploration)
|
|
19
|
+
- [模型体验](#model-experience)
|
|
20
|
+
- [已知限制与延期工作](#known-limitations-and-deferred-work)
|
|
21
|
+
- [开发备注](#dev-note)
|
|
22
|
+
|
|
23
|
+
-----
|
|
24
|
+
|
|
25
|
+
<a id="use-this-package"></a>
|
|
26
|
+
## 使用本包
|
|
27
|
+
|
|
28
|
+
与 `ui-conversation` 一起挂载本插件;Like/Dislike 对随即出现在每个轮次收尾助手消息的动作行中,位于复制与分支之间。再次点击已记录的评分会撤回反馈;切换到另一侧会保留既有备注。备注编辑器是一个锚定在其触发按钮下方的对话框浮层,因此无论编辑器是否打开,该行都保持单行。
|
|
29
|
+
|
|
30
|
+
### 失败
|
|
31
|
+
|
|
32
|
+
评分或列表加载失败在行内展示;备注保存失败在浮层内展示,面板保持打开以便修正草稿。只有已定稿的消息能到达该槽位——被中断冻结的部分输出不带 `messageId`,因此没有反馈控件。
|
|
33
|
+
|
|
34
|
+
-----
|
|
35
|
+
|
|
36
|
+
<a id="understand-the-implementation"></a>
|
|
37
|
+
## 理解实现
|
|
38
|
+
|
|
39
|
+
<details>
|
|
40
|
+
<summary>实现细节——点击展开</summary>
|
|
6
41
|
|
|
7
|
-
|
|
42
|
+
本包贡献 `conversation.chat.assistant-actions` 的 `feedback` 条目(order 10),由 ui-conversation 声明并渲染在已定稿助手消息的 IconActions 行内。每个 Session 一个 `MessageFeedbackController` 支撑该 Session 内所有消息的控件,因此一次 `messageFeedback.list` 读取即可填充整段对话;该读取延迟到首次 hover 或 focus 才发起,而非挂载时触发。变更经 `ctx.remote.messageFeedback` 提交,按条目的比较并交换由宿主负责。每次 `put` 与 `delete` 都携带本控制器最后观察到的 `version`;`version-conflict` 响应带回权威条目,因此竞争失败时直接用该响应本身对账,无需重新拉取。变更按 Session 串行,排队中的操作总是与已提交的版本比较。
|
|
8
43
|
|
|
9
|
-
|
|
44
|
+
</details>
|
|
10
45
|
|
|
11
|
-
|
|
46
|
+
-----
|
|
12
47
|
|
|
48
|
+
<a id="further-exploration"></a>
|
|
49
|
+
## 进一步探索
|
|
50
|
+
|
|
51
|
+
当反馈面不够用时阅读以下页面。它们从浏览器条带进入 sidecar 后端与会话外壳。
|
|
52
|
+
|
|
53
|
+
- [dsh-message-feedback](../../feedback/message-feedback/README.zh.md)——拥有按条目比较并交换的 sidecar 后端。
|
|
54
|
+
- [ui-conversation](../ui-conversation/README.zh.md)——声明助手动作条并渲染动作行。
|
|
55
|
+
- [客户端包映射](../README.zh.md)——相邻的浏览器 UI 包。
|
|
56
|
+
|
|
57
|
+
-----
|
|
58
|
+
|
|
59
|
+
<a id="model-experience"></a>
|
|
13
60
|
## 模型体验
|
|
14
61
|
|
|
15
62
|
无。反馈是 sidecar,不进入 append-only 的 Session 日志、模型上下文或遥测;任何评分与备注对模型都不可见。
|
|
@@ -18,8 +65,23 @@
|
|
|
18
65
|
|
|
19
66
|
无;任何反馈变更都不触碰历史尾部。
|
|
20
67
|
|
|
21
|
-
##
|
|
68
|
+
## 已知限制与延期工作
|
|
69
|
+
|
|
70
|
+
<a id="known-limitations-and-deferred-work"></a>
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
这些限制界定了当前反馈表面。它们是当前包约束,不是通用评分对比或任务积压。
|
|
74
|
+
|
|
75
|
+
- **备注大小是宿主策略**——部署方配置 `maxNoteBytes`(Web bundle 中为 8192),超长备注由宿主以 `note-too-large` 拒绝。编辑器不预先校验该上限,因此超长备注在保存时才失败,而不是在输入过程中。
|
|
76
|
+
- **无跨标签页推送**——另一个标签页的评分要等到重连或下一次冲突响应才可见,不会立即出现;该 sidecar 不发布实时帧。
|
|
77
|
+
- **仅限对话视图**——trajectory 与 waterfall 视图不渲染反馈控件,尽管它们的助手节点也带有相同的 `messageId`。
|
|
78
|
+
|
|
79
|
+
<a id="dev-note"></a>
|
|
80
|
+
### 开发备注
|
|
81
|
+
|
|
82
|
+
<details>
|
|
83
|
+
<summary>维护者的工作上下文——点击展开</summary>
|
|
84
|
+
|
|
85
|
+
无。
|
|
22
86
|
|
|
23
|
-
|
|
24
|
-
- **无跨标签页推送** —— 另一个标签页的评分要等到重连或下一次冲突响应才可见,不会立即出现;该 sidecar 不发布实时帧。
|
|
25
|
-
- **仅限对话视图** —— trajectory 与 waterfall 视图不渲染反馈控件,尽管它们的助手节点现在也带有相同的 `messageId`。
|
|
87
|
+
</details>
|
package/lib/client.js
CHANGED
|
@@ -58,7 +58,7 @@ window.__ModuleLoader__.load({
|
|
|
58
58
|
* control in that Session, so a single list read seeds them all.
|
|
59
59
|
*/
|
|
60
60
|
var MessageFeedbackController = class {
|
|
61
|
-
|
|
61
|
+
ctx;
|
|
62
62
|
sessionId;
|
|
63
63
|
view = INITIAL_VIEW;
|
|
64
64
|
listeners = /* @__PURE__ */ new Set();
|
|
@@ -66,11 +66,11 @@ window.__ModuleLoader__.load({
|
|
|
66
66
|
operationTail = Promise.resolve();
|
|
67
67
|
disposed = false;
|
|
68
68
|
/**
|
|
69
|
-
* @param
|
|
69
|
+
* @param ctx - the browser plugin context carrying the messageFeedback Remote namespace.
|
|
70
70
|
* @param sessionId - Session owning every addressed assistant message.
|
|
71
71
|
*/
|
|
72
|
-
constructor(
|
|
73
|
-
this.
|
|
72
|
+
constructor(ctx, sessionId) {
|
|
73
|
+
this.ctx = ctx;
|
|
74
74
|
this.sessionId = sessionId;
|
|
75
75
|
}
|
|
76
76
|
/** Return the cached immutable view. */
|
|
@@ -185,7 +185,7 @@ window.__ModuleLoader__.load({
|
|
|
185
185
|
}
|
|
186
186
|
/** Commit one put against the observed version and reconcile a conflict. */
|
|
187
187
|
async putCommitted(messageId, rating, note, observed) {
|
|
188
|
-
const carried = await this.remote.put({
|
|
188
|
+
const carried = await this.ctx.remote.messageFeedback.put({
|
|
189
189
|
sessionId: this.sessionId,
|
|
190
190
|
messageId,
|
|
191
191
|
rating,
|
|
@@ -203,7 +203,7 @@ window.__ModuleLoader__.load({
|
|
|
203
203
|
}
|
|
204
204
|
/** Commit one delete against the observed version and reconcile a conflict. */
|
|
205
205
|
async deleteCommitted(messageId, observed) {
|
|
206
|
-
const carried = await this.remote.delete({
|
|
206
|
+
const carried = await this.ctx.remote.messageFeedback.delete({
|
|
207
207
|
sessionId: this.sessionId,
|
|
208
208
|
messageId,
|
|
209
209
|
ifVersion: observed.version
|
|
@@ -224,55 +224,37 @@ window.__ModuleLoader__.load({
|
|
|
224
224
|
}
|
|
225
225
|
/** Fetch the whole sidecar and publish it as the seeded view. */
|
|
226
226
|
async load() {
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
if (!carried.ok) {
|
|
231
|
-
this.publish({
|
|
232
|
-
status: "error",
|
|
233
|
-
items: this.view.items,
|
|
234
|
-
error: carried.error.message
|
|
235
|
-
});
|
|
236
|
-
return carrierFailure(carried.error);
|
|
237
|
-
}
|
|
238
|
-
const result = carried.value;
|
|
239
|
-
if (!result.ok) {
|
|
240
|
-
this.publish({
|
|
241
|
-
status: "error",
|
|
242
|
-
items: this.view.items,
|
|
243
|
-
error: describe(result.error.code)
|
|
244
|
-
});
|
|
245
|
-
return fail(result.error.code);
|
|
246
|
-
}
|
|
247
|
-
const items = /* @__PURE__ */ new Map();
|
|
248
|
-
for (const item of result.value.items) items.set(item.messageId, item);
|
|
227
|
+
const carried = await this.ctx.remote.messageFeedback.list({ sessionId: this.sessionId });
|
|
228
|
+
if (this.disposed) return OK;
|
|
229
|
+
if (!carried.ok) {
|
|
249
230
|
this.publish({
|
|
250
|
-
status: "
|
|
251
|
-
items,
|
|
252
|
-
error:
|
|
231
|
+
status: "error",
|
|
232
|
+
items: this.view.items,
|
|
233
|
+
error: carried.error.message
|
|
253
234
|
});
|
|
254
|
-
return
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
|
|
235
|
+
return carrierFailure(carried.error);
|
|
236
|
+
}
|
|
237
|
+
const result = carried.value;
|
|
238
|
+
if (!result.ok) {
|
|
258
239
|
this.publish({
|
|
259
240
|
status: "error",
|
|
260
241
|
items: this.view.items,
|
|
261
|
-
error:
|
|
242
|
+
error: describe(result.error.code)
|
|
262
243
|
});
|
|
263
|
-
return
|
|
264
|
-
ok: false,
|
|
265
|
-
error: {
|
|
266
|
-
code: "transport",
|
|
267
|
-
message
|
|
268
|
-
}
|
|
269
|
-
};
|
|
244
|
+
return fail(result.error.code);
|
|
270
245
|
}
|
|
246
|
+
const items = /* @__PURE__ */ new Map();
|
|
247
|
+
for (const item of result.value.items) items.set(item.messageId, item);
|
|
248
|
+
this.publish({
|
|
249
|
+
status: "ready",
|
|
250
|
+
items,
|
|
251
|
+
error: null
|
|
252
|
+
});
|
|
253
|
+
return OK;
|
|
271
254
|
}
|
|
272
255
|
/**
|
|
273
256
|
* Serialize one mutation behind this Session's prior mutation so queued
|
|
274
|
-
* operations always compare against the committed version
|
|
275
|
-
* transport throw into the same settled shape the controls already render.
|
|
257
|
+
* operations always compare against the committed version.
|
|
276
258
|
*/
|
|
277
259
|
mutate(operation, options = {}) {
|
|
278
260
|
const guarded = async () => {
|
|
@@ -282,17 +264,7 @@ window.__ModuleLoader__.load({
|
|
|
282
264
|
if (!loaded.ok) return loaded;
|
|
283
265
|
if (this.disposed) return DISPOSED;
|
|
284
266
|
}
|
|
285
|
-
|
|
286
|
-
return await operation();
|
|
287
|
-
} catch (error) {
|
|
288
|
-
return {
|
|
289
|
-
ok: false,
|
|
290
|
-
error: {
|
|
291
|
-
code: "transport",
|
|
292
|
-
message: error instanceof Error ? error.message : "message feedback mutation failed"
|
|
293
|
-
}
|
|
294
|
-
};
|
|
295
|
-
}
|
|
267
|
+
return await operation();
|
|
296
268
|
};
|
|
297
269
|
const result = this.operationTail.then(guarded, guarded);
|
|
298
270
|
this.operationTail = result.then(() => void 0);
|
|
@@ -326,7 +298,7 @@ window.__ModuleLoader__.load({
|
|
|
326
298
|
};
|
|
327
299
|
//#endregion
|
|
328
300
|
//#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/client/ui-message-feedback/src/client/MessageFeedbackActions.module.css.mjs
|
|
329
|
-
const css = "._8_XoUG_action{width:28px;height:28px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;border-radius:28px;justify-content:center;align-items:center;padding:6px;display:inline-flex}._8_XoUG_action:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary)}._8_XoUG_action:disabled{cursor:default;opacity:.4}._8_XoUG_action[data-active]{color:var(--dsw-alias-label-primary)}._8_XoUG_noteOpen{max-width:220px;color:var(--dsw-alias-label-tertiary);white-space:nowrap;text-overflow:ellipsis;cursor:pointer;background:0 0;border:none;border-radius:14px;padding:0 8px;
|
|
301
|
+
const css = "._8_XoUG_action{width:calc(28px + var(--dsh-content-font-delta,0px));height:calc(28px + var(--dsh-content-font-delta,0px));color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;border-radius:28px;justify-content:center;align-items:center;padding:6px;display:inline-flex}._8_XoUG_action svg{width:calc(15px + var(--dsh-content-font-delta,0px));height:calc(15px + var(--dsh-content-font-delta,0px))}._8_XoUG_action:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary)}._8_XoUG_action:disabled{cursor:default;opacity:.4}._8_XoUG_action[data-active]{color:var(--dsw-alias-label-primary)}._8_XoUG_noteOpen{max-width:220px;color:var(--dsw-alias-label-tertiary);font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(28px + var(--dsh-content-font-delta,0px));white-space:nowrap;text-overflow:ellipsis;cursor:pointer;background:0 0;border:none;border-radius:14px;padding:0 8px;overflow:hidden}._8_XoUG_noteOpen:hover,._8_XoUG_noteOpen[aria-expanded=true]{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary)}._8_XoUG_notePanel{z-index:1100;box-sizing:border-box;border:1px solid var(--dsw-alias-border-inverted);background:var(--dsw-specific-menu);width:320px;max-width:min(360px,100vw - 24px);max-height:calc(100vh - 24px);box-shadow:var(--dsw-shadow-lv3);--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);border-radius:12px;flex-direction:column;gap:8px;padding:8px;display:flex;position:fixed;overflow-y:auto}._8_XoUG_noteInput{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);width:100%;color:var(--dsw-alias-label-primary);font:inherit;resize:vertical;border-radius:8px;padding:6px 8px;font-size:13px}._8_XoUG_noteActions{justify-content:flex-end;gap:6px;display:flex}._8_XoUG_noteSave,._8_XoUG_noteCancel{cursor:pointer;border:none;border-radius:14px;height:28px;padding:0 10px;font-size:13px}._8_XoUG_noteSave{background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground)}._8_XoUG_noteSave:hover:not(:disabled){background:var(--dsw-alias-button-primary-hover)}._8_XoUG_noteSave:disabled{cursor:default;opacity:.4}._8_XoUG_noteCancel{color:var(--dsw-alias-label-tertiary);background:0 0}._8_XoUG_noteCancel:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary)}._8_XoUG_failure{color:var(--dsw-alias-label-tertiary);padding-left:4px;font-size:13px;line-height:20px}";
|
|
330
302
|
const tagId = "@deepseek-ai/dsh-client-ui-message-feedback/MessageFeedbackActions.module.css";
|
|
331
303
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
332
304
|
const tag = document.createElement("style");
|
|
@@ -684,7 +656,7 @@ window.__ModuleLoader__.load({
|
|
|
684
656
|
const controllerFor = (sessionId) => {
|
|
685
657
|
let controller = controllers.get(sessionId);
|
|
686
658
|
if (controller === void 0) {
|
|
687
|
-
controller = new MessageFeedbackController(ctx
|
|
659
|
+
controller = new MessageFeedbackController(ctx, sessionId);
|
|
688
660
|
controllers.set(sessionId, controller);
|
|
689
661
|
}
|
|
690
662
|
return controller;
|
|
@@ -6,33 +6,11 @@
|
|
|
6
6
|
* instead of refetching the whole Session.
|
|
7
7
|
* @module @deepseek-ai/dsh-client-ui-message-feedback/client/controller
|
|
8
8
|
*/
|
|
9
|
-
import type {
|
|
9
|
+
import type { Context as ClientContext } from '@deepseek-ai/cordis';
|
|
10
10
|
import type { HostObservable } from '@deepseek-ai/dsh-client-ui-slots';
|
|
11
|
-
import type { MessageId
|
|
12
|
-
import type {
|
|
13
|
-
|
|
14
|
-
* The three Remote calls this controller needs. The generated face wraps every
|
|
15
|
-
* business result in {@link RemoteResult}: a carrier failure arrives as the
|
|
16
|
-
* `ok: false` branch rather than a rejection, so this controller reads one
|
|
17
|
-
* envelope and never wraps a call to recover a transport error.
|
|
18
|
-
*/
|
|
19
|
-
export interface MessageFeedbackRemote {
|
|
20
|
-
list: (request: {
|
|
21
|
-
sessionId: SessionId;
|
|
22
|
-
}) => Promise<RemoteResult<MessageFeedbackListResult>>;
|
|
23
|
-
put: (request: {
|
|
24
|
-
sessionId: SessionId;
|
|
25
|
-
messageId: MessageId;
|
|
26
|
-
rating: MessageFeedbackRating;
|
|
27
|
-
note?: string;
|
|
28
|
-
ifVersion: MessageFeedbackItem['version'] | null;
|
|
29
|
-
}) => Promise<RemoteResult<MessageFeedbackPutResult>>;
|
|
30
|
-
delete: (request: {
|
|
31
|
-
sessionId: SessionId;
|
|
32
|
-
messageId: MessageId;
|
|
33
|
-
ifVersion: MessageFeedbackItem['version'];
|
|
34
|
-
}) => Promise<RemoteResult<MessageFeedbackDeleteResult>>;
|
|
35
|
-
}
|
|
11
|
+
import type { MessageId } from '@deepseek-ai/dsh-api-remotes/client';
|
|
12
|
+
import type { SessionId } from '@deepseek-ai/dsh-session/types';
|
|
13
|
+
import type { MessageFeedbackItem, MessageFeedbackRating } from '@deepseek-ai/dsh-message-feedback/types';
|
|
36
14
|
/** Load state of the one list read that seeds every per-message control. */
|
|
37
15
|
export type MessageFeedbackStatus = 'cold' | 'loading' | 'ready' | 'error';
|
|
38
16
|
/** Immutable view published to every per-message control in one Session. */
|
|
@@ -58,7 +36,7 @@ export type MessageFeedbackActionResult = {
|
|
|
58
36
|
* control in that Session, so a single list read seeds them all.
|
|
59
37
|
*/
|
|
60
38
|
export declare class MessageFeedbackController implements HostObservable<MessageFeedbackView> {
|
|
61
|
-
private readonly
|
|
39
|
+
private readonly ctx;
|
|
62
40
|
private readonly sessionId;
|
|
63
41
|
private view;
|
|
64
42
|
private readonly listeners;
|
|
@@ -66,10 +44,10 @@ export declare class MessageFeedbackController implements HostObservable<Message
|
|
|
66
44
|
private operationTail;
|
|
67
45
|
private disposed;
|
|
68
46
|
/**
|
|
69
|
-
* @param
|
|
47
|
+
* @param ctx - the browser plugin context carrying the messageFeedback Remote namespace.
|
|
70
48
|
* @param sessionId - Session owning every addressed assistant message.
|
|
71
49
|
*/
|
|
72
|
-
constructor(
|
|
50
|
+
constructor(ctx: ClientContext, sessionId: SessionId);
|
|
73
51
|
/** Return the cached immutable view. */
|
|
74
52
|
getSnapshot: () => MessageFeedbackView;
|
|
75
53
|
/** Subscribe to view replacement. */
|
|
@@ -145,8 +123,7 @@ export declare class MessageFeedbackController implements HostObservable<Message
|
|
|
145
123
|
private load;
|
|
146
124
|
/**
|
|
147
125
|
* Serialize one mutation behind this Session's prior mutation so queued
|
|
148
|
-
* operations always compare against the committed version
|
|
149
|
-
* transport throw into the same settled shape the controls already render.
|
|
126
|
+
* operations always compare against the committed version.
|
|
150
127
|
*/
|
|
151
128
|
private mutate;
|
|
152
129
|
/**
|
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
* messageFeedback Remote; the Host owns per-item compare-and-set.
|
|
7
7
|
* @module @deepseek-ai/dsh-client-ui-message-feedback/client
|
|
8
8
|
*/
|
|
9
|
-
import type { ClientContext } from '@deepseek-ai/
|
|
10
|
-
export type { MessageFeedbackActionResult, MessageFeedbackStatus, MessageFeedbackView,
|
|
9
|
+
import type { Context as ClientContext } from '@deepseek-ai/cordis';
|
|
10
|
+
export type { MessageFeedbackActionResult, MessageFeedbackStatus, MessageFeedbackView, } from './controller.ts';
|
|
11
11
|
export type { MessageFeedbackActionProps, MessageFeedbackInjected } from './slots.ts';
|
|
12
12
|
export type { MessageFeedbackKey } from './locales.ts';
|
|
13
13
|
/** Required services: the slot registry, the Remote namespace, and the copy. */
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* @module @deepseek-ai/dsh-client-ui-message-feedback/client/slots
|
|
9
9
|
*/
|
|
10
10
|
import type { HostObservable, InjectFace, PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
|
|
11
|
-
import type { MessageId } from '@deepseek-ai/dsh-
|
|
11
|
+
import type { MessageId } from '@deepseek-ai/dsh-api-remotes/client';
|
|
12
12
|
import type { MessageFeedbackRating } from '@deepseek-ai/dsh-message-feedback/types';
|
|
13
13
|
import type { MessageFeedbackActionResult, MessageFeedbackView } from './controller.ts';
|
|
14
14
|
/** Injected business face of one assistant-message feedback entry. */
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deepseek-ai/dsh-client-ui-message-feedback",
|
|
3
3
|
"description": "Per-message feedback controls contributed to the assistant-message action strip, backed by the messageFeedback Host Remote",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.2-alpha.3",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -32,25 +32,17 @@
|
|
|
32
32
|
"dsh": {
|
|
33
33
|
"client": {
|
|
34
34
|
"inject": [
|
|
35
|
-
"@deepseek-ai/dsh-client-runtime",
|
|
36
35
|
"@deepseek-ai/dsh-api-remotes",
|
|
37
36
|
"@deepseek-ai/dsh-client-locale",
|
|
38
|
-
"@deepseek-ai/dsh-client-ui-conversation"
|
|
37
|
+
"@deepseek-ai/dsh-client-ui-conversation",
|
|
38
|
+
"@deepseek-ai/dsh-client-ui-renderer"
|
|
39
39
|
],
|
|
40
40
|
"platform": "web"
|
|
41
41
|
}
|
|
42
42
|
},
|
|
43
43
|
"license": "MIT",
|
|
44
44
|
"peerDependencies": {
|
|
45
|
-
"@deepseek-ai/
|
|
46
|
-
"@deepseek-ai/dsh-client-connection": "^0.1.1-rc.2",
|
|
47
|
-
"@deepseek-ai/dsh-client-locale": "^0.1.1-rc.2",
|
|
48
|
-
"@deepseek-ai/dsh-client-ui-conversation": "^0.1.1-rc.2",
|
|
49
|
-
"@deepseek-ai/dsh-invariants": "^0.1.1-rc.2",
|
|
50
|
-
"@deepseek-ai/dsh-message-feedback": "^0.1.1-rc.2",
|
|
51
|
-
"@deepseek-ai/dsh-typert-protocol": "^0.1.1-rc.2",
|
|
52
|
-
"@deepseek-ai/dsh-client-runtime": "^0.1.1-rc.2",
|
|
53
|
-
"@deepseek-ai/cordis": "^4.0.1"
|
|
45
|
+
"@deepseek-ai/cordis": "^4.0.2"
|
|
54
46
|
},
|
|
55
47
|
"devDependencies": {
|
|
56
48
|
"@testing-library/react": "^16.1.0",
|
|
@@ -58,18 +50,21 @@
|
|
|
58
50
|
"@types/react-dom": "~18.3.0",
|
|
59
51
|
"react": "^18.2.0",
|
|
60
52
|
"react-dom": "^18.2.0",
|
|
61
|
-
"@deepseek-ai/dsh-
|
|
62
|
-
"@deepseek-ai/dsh-
|
|
63
|
-
"@deepseek-ai/dsh-client-
|
|
64
|
-
"@deepseek-ai/dsh-client-
|
|
65
|
-
"@deepseek-ai/dsh-client-
|
|
66
|
-
"@deepseek-ai/dsh-client-ui-
|
|
67
|
-
"@deepseek-ai/dsh-client-ui-slots": "^0.1.
|
|
68
|
-
"@deepseek-ai/dsh-
|
|
69
|
-
"@deepseek-ai/dsh-
|
|
70
|
-
"@deepseek-ai/
|
|
71
|
-
"@deepseek-ai/dsh-
|
|
72
|
-
"@deepseek-ai/
|
|
53
|
+
"@deepseek-ai/dsh-api-remotes": "^0.1.2-alpha.3",
|
|
54
|
+
"@deepseek-ai/dsh-client-connection": "^0.1.2-alpha.3",
|
|
55
|
+
"@deepseek-ai/dsh-client-test-runtime": "^0.1.2-alpha.3",
|
|
56
|
+
"@deepseek-ai/dsh-client-ui-conversation": "^0.1.2-alpha.3",
|
|
57
|
+
"@deepseek-ai/dsh-client-locale": "^0.1.2-alpha.3",
|
|
58
|
+
"@deepseek-ai/dsh-client-ui-primitives": "^0.1.2-alpha.3",
|
|
59
|
+
"@deepseek-ai/dsh-client-ui-slots": "^0.1.2-alpha.3",
|
|
60
|
+
"@deepseek-ai/dsh-client-ui-renderer": "^0.1.2-alpha.3",
|
|
61
|
+
"@deepseek-ai/dsh-invariants": "^0.1.2-alpha.3",
|
|
62
|
+
"@deepseek-ai/dsh-message-feedback": "^0.1.2-alpha.3",
|
|
63
|
+
"@deepseek-ai/dsh-typert-protocol": "^0.1.2-alpha.3",
|
|
64
|
+
"@deepseek-ai/cordis": "^4.0.2",
|
|
65
|
+
"@deepseek-ai/dsh-session": "^0.1.2-alpha.3",
|
|
66
|
+
"@deepseek-ai/dsh-client-ui-session": "^0.1.2-alpha.3",
|
|
67
|
+
"@deepseek-ai/dsh-client-ui-chat": "^0.1.2-alpha.3"
|
|
73
68
|
},
|
|
74
69
|
"files": [
|
|
75
70
|
"lib/index.js",
|