@morlay/ui-conversation-message-actions 0.0.19-alpha.5 → 0.0.19-alpha.6

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/dist/client.cjs CHANGED
@@ -29,13 +29,18 @@ window.__ModuleLoader__.load({
29
29
  turn,
30
30
  cascade
31
31
  }),
32
- recall: (message, texts) => this.mutate({
33
- action: "recall",
34
- sessionId: this.sessionId,
35
- eventSeq: message.eventSeq
36
- }, () => this.setComposerDraft(texts.join("\n\n")))
32
+ recall: (message, texts) => this.recallAndEdit(message, texts)
37
33
  };
38
34
  }
35
+ async recallAndEdit(message, texts) {
36
+ const applied = await this.mutate({
37
+ action: "recall",
38
+ sessionId: this.sessionId,
39
+ eventSeq: message.eventSeq
40
+ }, () => this.setComposerDraft(texts.join("\n\n")));
41
+ if (applied) this.returnViewportToEnd();
42
+ return applied;
43
+ }
39
44
  async mutate(operation, onApplied) {
40
45
  if (this.pending !== null) return false;
41
46
  this.pending = operation.action;
@@ -86,6 +91,23 @@ window.__ModuleLoader__.load({
86
91
  }
87
92
  console.warn("[session-editor] 未找到会话窗口重建入口(binding.resync / refresh 都不可用),窗口可能停留在 rewind 之前的状态");
88
93
  }
94
+ /**
95
+ * 撤回后把会话视口送回底部:rewind 把窗口换短,而上游 ChatView 只在读者已经贴底时
96
+ * 才跟随(`tipMoved && atBottom`),停在中途的视口会悬在被截断的位置上;撤回的下一步
97
+ * 是改完再发,所以这里无条件送到底。容器用上游既有契约 `[data-conversation-scroll]`
98
+ * (ChatView / ConversationWidthControls / StatsPills 同用)。
99
+ *
100
+ * 窗口替换的渲染落在 resync 之后:写早了会被下一轮布局覆盖,因此等两帧再写。
101
+ */
102
+ returnViewportToEnd() {
103
+ const scrollport = document.querySelector("[data-conversation-scroll]");
104
+ if (scrollport === null) return;
105
+ requestAnimationFrame(() => {
106
+ requestAnimationFrame(() => {
107
+ scrollport.scrollTop = scrollport.scrollHeight;
108
+ });
109
+ });
110
+ }
89
111
  setComposerDraft(text) {
90
112
  if (this.sessions.binding(this.sessionId) === void 0) return;
91
113
  const scoped = this.sessions.scope(this.sessionId);
@@ -108,19 +130,6 @@ window.__ModuleLoader__.load({
108
130
  next.setHours(24, 0, 0, 0);
109
131
  return Math.max(next.getTime() - ms, 1);
110
132
  }
111
- function formatRunDuration(ms, t) {
112
- const total = Math.max(0, Math.floor(ms / 1e3));
113
- const minutes = Math.floor(total / 60);
114
- const seconds = total % 60;
115
- return minutes > 0 ? t("duration.minutes", {
116
- minutes,
117
- seconds: String(seconds).padStart(2, "0")
118
- }) : t("duration.seconds", { seconds });
119
- }
120
- function formatLatencySeconds(ms) {
121
- const s = Math.max(0, ms) / 1e3;
122
- return s < 10 ? String(Math.round(s * 10) / 10) : String(Math.round(s));
123
- }
124
133
  function formatTokensPerSecond(tps) {
125
134
  const clamped = Math.max(0, tps);
126
135
  return clamped >= 10 ? String(Math.round(clamped)) : String(Math.round(clamped * 10) / 10);
@@ -223,7 +232,7 @@ window.__ModuleLoader__.load({
223
232
  };
224
233
  //#endregion
225
234
  //#region src/client/chat-node/MessageIconActions.tsx
226
- function MessageIconActions({ text, time, runMs, ttftMs, tokensPerSecond, clock, onBranch, branchUnavailable = false, className, extraActions, onEdit, onRetry, t }) {
235
+ function MessageIconActions({ text, time, clock, onBranch, branchUnavailable = false, className, extraActions, onEdit, onRetry, t }) {
227
236
  const day = useCalendarDay();
228
237
  const reasonId = (0, react.useId)();
229
238
  const [copied, setCopied] = (0, react.useState)(false);
@@ -250,44 +259,10 @@ window.__ModuleLoader__.load({
250
259
  }, 1e3);
251
260
  });
252
261
  }, [copied, text]);
253
- const clockEl = time === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
262
+ const clockEl = time === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
254
263
  "data-time-label": "",
255
264
  ..._morlay_dsh_client_ui_primitives_client.styling.props(clock === "start" ? styles$3.timeStart : styles$3.timeEnd),
256
- children: [
257
- formatMessageClock(time, t, day),
258
- runMs !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
259
- " ",
260
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
261
- ..._morlay_dsh_client_ui_primitives_client.styling.props(styles$3.runTimeDot),
262
- "aria-hidden": true,
263
- children: "·"
264
- }),
265
- " ",
266
- t("message.ranFor", { duration: formatRunDuration(runMs, t) })
267
- ] }),
268
- ttftMs !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
269
- " ",
270
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
271
- ..._morlay_dsh_client_ui_primitives_client.styling.props(styles$3.runTimeDot),
272
- "aria-hidden": true,
273
- children: "·"
274
- }),
275
- " ",
276
- t("message.turnTime.ttft"),
277
- " ",
278
- t("duration.seconds", { seconds: formatLatencySeconds(ttftMs) })
279
- ] }),
280
- tokensPerSecond !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
281
- " ",
282
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
283
- ..._morlay_dsh_client_ui_primitives_client.styling.props(styles$3.runTimeDot),
284
- "aria-hidden": true,
285
- children: "·"
286
- }),
287
- " ",
288
- t("message.tokensPerSecond", { tps: formatTokensPerSecond(tokensPerSecond) })
289
- ] })
290
- ]
265
+ children: formatMessageClock(time, t, day)
291
266
  });
292
267
  const actionsClass = _morlay_dsh_client_ui_primitives_client.styling.className(styles$3.actions);
293
268
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
@@ -303,7 +278,7 @@ window.__ModuleLoader__.load({
303
278
  ..._morlay_dsh_client_ui_primitives_client.styling.props(styles$3.action),
304
279
  "aria-label": copied ? t("copied") : t("copy"),
305
280
  onClick: onCopy,
306
- children: copied ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCheckOutline16, {}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCopyOutline16, {})
281
+ children: copied ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCheckOutlineRegular, {}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCopyOutlineRegular, {})
307
282
  })
308
283
  }),
309
284
  extraActions,
@@ -315,7 +290,7 @@ window.__ModuleLoader__.load({
315
290
  ..._morlay_dsh_client_ui_primitives_client.styling.props(styles$3.action),
316
291
  "aria-label": "编辑",
317
292
  onClick: onEdit,
318
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconEditOutline16, {})
293
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconEditOutlineRegular, {})
319
294
  })
320
295
  }),
321
296
  onRetry !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
@@ -326,7 +301,7 @@ window.__ModuleLoader__.load({
326
301
  ..._morlay_dsh_client_ui_primitives_client.styling.props(styles$3.action),
327
302
  "aria-label": "重试此回合",
328
303
  onClick: onRetry,
329
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconRefreshOutline16, {})
304
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconRefreshOutlineRegular, {})
330
305
  })
331
306
  }),
332
307
  onBranch !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
@@ -340,7 +315,7 @@ window.__ModuleLoader__.load({
340
315
  "aria-describedby": branchUnavailable ? reasonId : void 0,
341
316
  "data-unavailable": branchUnavailable || void 0,
342
317
  onClick: branchUnavailable ? void 0 : onBranch,
343
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconBranchOutline16, {})
318
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconBranchOutlineRegular, {})
344
319
  })
345
320
  }),
346
321
  onBranch !== void 0 && branchUnavailable && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
@@ -1052,7 +1027,7 @@ window.__ModuleLoader__.load({
1052
1027
  ..._morlay_dsh_client_ui_primitives_client.styling.props(styles$1.anchor),
1053
1028
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1054
1029
  ..._morlay_dsh_client_ui_primitives_client.styling.props(styles$1.pill),
1055
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconGaugeOutline16, {}), label]
1030
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconGaugeOutlineRegular, {}), label]
1056
1031
  })
1057
1032
  });
1058
1033
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
@@ -1067,7 +1042,7 @@ window.__ModuleLoader__.load({
1067
1042
  onClick: () => {
1068
1043
  setOpen(!open);
1069
1044
  },
1070
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconGaugeOutline16, {}), label]
1045
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconGaugeOutlineRegular, {}), label]
1071
1046
  }), open && (0, react_dom.createPortal)(/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1072
1047
  ref: panelRef,
1073
1048
  ..._morlay_dsh_client_ui_primitives_client.styling.props(styles.panel),
@@ -1079,7 +1054,7 @@ window.__ModuleLoader__.load({
1079
1054
  ..._morlay_dsh_client_ui_primitives_client.styling.props(styles.title),
1080
1055
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1081
1056
  ..._morlay_dsh_client_ui_primitives_client.styling.props(styles.titleLabel),
1082
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconGaugeOutline16, {}), t("stats.dialog.title")]
1057
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconGaugeOutlineRegular, {}), t("stats.dialog.title")]
1083
1058
  })
1084
1059
  }),
1085
1060
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -1118,7 +1093,7 @@ window.__ModuleLoader__.load({
1118
1093
  onClick: () => {
1119
1094
  setOpen(!open);
1120
1095
  },
1121
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconDatabaseOutline16, {}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1096
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconDatabaseOutlineRegular, {}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1122
1097
  ..._morlay_dsh_client_ui_primitives_client.styling.props(styles$1.label),
1123
1098
  children: [totalText, cacheHitText !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1124
1099
  ..._morlay_dsh_client_ui_primitives_client.styling.props(styles$1.sep),
@@ -1137,7 +1112,7 @@ window.__ModuleLoader__.load({
1137
1112
  ..._morlay_dsh_client_ui_primitives_client.styling.props(styles.title),
1138
1113
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1139
1114
  ..._morlay_dsh_client_ui_primitives_client.styling.props(styles.titleLabel),
1140
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconDatabaseOutline16, {}), t("stats.dialog.usageTitle")]
1115
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconDatabaseOutlineRegular, {}), t("stats.dialog.usageTitle")]
1141
1116
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1142
1117
  ..._morlay_dsh_client_ui_primitives_client.styling.props(styles.titleValue),
1143
1118
  children: exactCount(total, t)
package/dist/index.mjs CHANGED
@@ -68,7 +68,7 @@ var SessionEditor = class extends Service {
68
68
  ];
69
69
  constructor(ctx) {
70
70
  super(ctx, "sessionEditor");
71
- registerHttpRoutes(ctx);
71
+ registerHttpRoutes(ctx, this);
72
72
  }
73
73
  readBranchPrefix(id, atSeq, mode, signal) {
74
74
  return this.ctx.sessionBranch.readBranchPrefix(id, atSeq, mode, signal);
@@ -367,17 +367,16 @@ async function handleRoute(editor, request, response) {
367
367
  respondJson(response, error instanceof TypeError ? 400 : 409, { error: message });
368
368
  }
369
369
  }
370
- function registerHttpRoutes(ctx) {
371
- ctx.effect(() => {
372
- const webServer = ctx.get("webServer");
373
- if (webServer === void 0) return () => {};
374
- const editor = ctx.sessionEditor;
375
- return webServer.register({
370
+ function registerHttpRoutes(ctx, editor) {
371
+ ctx.inject(["webServer"], (scope) => {
372
+ const webServer = scope.get("webServer");
373
+ if (webServer === void 0) return;
374
+ scope.effect(() => webServer.register({
376
375
  kind: "exact",
377
376
  path: SESSION_EDITOR_PATH,
378
377
  handler: (request, response) => handleRoute(editor, request, response)
379
- });
380
- }, "session-editor: HTTP route");
378
+ }), "session-editor: HTTP route");
379
+ });
381
380
  }
382
381
  //#endregion
383
382
  export { SessionEditor, SessionEditor as default, closedTurns, editableMessages, retryableTurns };