dsh-per-message-model 0.1.3 → 0.1.5

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.
Files changed (2) hide show
  1. package/lib/client.js +24 -9
  2. package/package.json +1 -1
package/lib/client.js CHANGED
@@ -231,7 +231,9 @@ window.__ModuleLoader__.load({
231
231
  React.useEffect(() => {
232
232
  if (typeof document === "undefined" || typeof MutationObserver === "undefined") return;
233
233
  let observer = null;
234
+ let timer = 0;
234
235
  const tryInsert = () => {
236
+ let remaining = 0;
235
237
  for (const sw of switches) {
236
238
  if (sw.to === null || typeof sw.to !== "object" ||
237
239
  typeof sw.to.provider !== "string" || typeof sw.to.model !== "string") continue;
@@ -247,22 +249,35 @@ window.__ModuleLoader__.load({
247
249
  const fromAnchor = document.querySelector('[data-chat-anchor-key="' + fromKey + '"]');
248
250
  const toAnchor = toKey !== null ? document.querySelector('[data-chat-anchor-key="' + toKey + '"]') : null;
249
251
  const anchor = fromAnchor !== null ? fromAnchor : toAnchor;
250
- if (anchor === null) continue;
252
+ if (anchor === null) { remaining += 1; continue; }
251
253
  const node = buildDividerNode(sw);
252
254
  node.setAttribute("data-from-seq", String(seqKey));
253
255
  if (fromAnchor !== null) fromAnchor.insertAdjacentElement("afterend", node);
254
256
  else toAnchor.insertAdjacentElement("beforebegin", node);
255
257
  }
258
+ return remaining;
256
259
  };
257
- tryInsert();
258
- // Keep repairing: windowed conversation rendering mounts/unmounts
259
- // chat nodes while scrolling, so dividers must be re-inserted on
260
- // any childList change. The callback is cheap (per-switch
261
- // querySelector + dedupe) and exits immediately once all exist.
262
- observer = new MutationObserver(() => tryInsert());
263
- observer.observe(document.body, { childList: true, subtree: true });
260
+ // Insert what is already rendered; watch (debounced) only while some
261
+ // anchors are still missing (windowed history loads them on scroll),
262
+ // and disconnect the moment everything is in place so a live
263
+ // session's continuous DOM churn can never re-trigger work.
264
+ const schedule = () => {
265
+ if (timer !== 0) return;
266
+ timer = setTimeout(() => {
267
+ timer = 0;
268
+ if (tryInsert() === 0 && observer !== null) {
269
+ observer.disconnect();
270
+ observer = null;
271
+ }
272
+ }, 150);
273
+ };
274
+ if (tryInsert() > 0) {
275
+ observer = new MutationObserver(schedule);
276
+ observer.observe(document.body, { childList: true, subtree: true });
277
+ }
264
278
  return () => {
265
279
  if (observer !== null) observer.disconnect();
280
+ if (timer !== 0) clearTimeout(timer);
266
281
  };
267
282
  }, [switches]);
268
283
  return null;
@@ -291,7 +306,7 @@ window.__ModuleLoader__.load({
291
306
  `[data-dsh-model-switch] [class*="-divider-model"]{flex:none;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dsw-alias-label-primary);font-weight:700}`,
292
307
  `[data-dsh-model-switch] [class*="-divider-arrow"]{flex:none;display:inline-flex;align-items:center;color:var(--dsw-alias-label-tertiary)}`,
293
308
  // Composer-dock model button: chip icon + unfoldable label (scroll).
294
- `[data-dsh-per-message-model-footer]{display:inline-flex;align-items:center;gap:6px;padding:4px 8px;border:1px solid var(--dsw-alias-border-l2, rgba(128,128,128,.25));border-radius:8px;background:transparent;color:var(--dsw-alias-label-tertiary);cursor:pointer;max-width:100%;overflow:hidden}`,
309
+ `[data-dsh-per-message-model-footer]{display:inline-flex;align-items:center;gap:6px;padding:4px 8px;border:1px solid var(--dsw-alias-border-l2, rgba(128,128,128,.25));border-radius:8px;background:transparent;color:var(--dsw-alias-label-tertiary);cursor:pointer;max-width:100%;width:fit-content;flex:none;overflow:hidden}`,
295
310
  `[data-dsh-per-message-model-footer]:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-hover, rgba(128,128,128,.12))}`,
296
311
  `[data-dsh-per-message-model-footer] [class*="-footer-icon"]{display:inline-flex;align-items:center;flex:none;transition:transform .45s cubic-bezier(.34,1.56,.64,1)}`,
297
312
  `[data-dsh-per-message-model-footer] [class*="-footer-label"]{display:inline-block;overflow:hidden;white-space:nowrap;max-width:0;opacity:0;transition:max-width .45s cubic-bezier(.4,0,.2,1),opacity .35s ease;font-size:12px;line-height:16px;color:var(--dsw-alias-label-primary);font-weight:600}`,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-per-message-model",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "在 DSH 主对话每条 assistant 回复旁展示该条回复实际使用的 provider / model 徽章(可选附带 reasoning effort)",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",