dsh-per-message-model 0.1.5 → 0.1.7
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/lib/client.js +33 -81
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -67,48 +67,6 @@ window.__ModuleLoader__.load({
|
|
|
67
67
|
})
|
|
68
68
|
]);
|
|
69
69
|
}
|
|
70
|
-
/**
|
|
71
|
-
* Per-message model badge as a small icon button. Missing projections
|
|
72
|
-
* degrade to the same icon with an unknown title (fail-soft, verifiable).
|
|
73
|
-
* @param value - a wire projection entry ({ provider, model, reasoningEffort, reasoningSource }).
|
|
74
|
-
* @param t - locale seat bound to this plugin's namespace.
|
|
75
|
-
*/
|
|
76
|
-
function modelBadge(value, t) {
|
|
77
|
-
const known = value !== null && typeof value === "object";
|
|
78
|
-
const provider = known && typeof value.provider === "string" ? value.provider : null;
|
|
79
|
-
const model = known && typeof value.model === "string" ? value.model : null;
|
|
80
|
-
const hasModel = provider !== null && model !== null;
|
|
81
|
-
const label = hasModel
|
|
82
|
-
? `${provider} / ${model}${t("badge.separator")}${t("badge.effort")} ${known && typeof value.reasoningEffort === "string" && value.reasoningEffort.length > 0 ? value.reasoningEffort : t("badge.effort.default")}`
|
|
83
|
-
: t("badge.unknown");
|
|
84
|
-
const title = hasModel && known && value.reasoningSource === "adapter-default"
|
|
85
|
-
? `${label}(${t("badge.effort.adapterDefault")})`
|
|
86
|
-
: hasModel ? label : t("badge.unknown.title");
|
|
87
|
-
return createElement("span", {
|
|
88
|
-
className: BADGE_PREFIX + "icon",
|
|
89
|
-
"data-dsh-per-message-model": "true",
|
|
90
|
-
"aria-label": label,
|
|
91
|
-
title
|
|
92
|
-
}, chipIcon());
|
|
93
|
-
}
|
|
94
|
-
/** Session-header occupant: current model badge (latest folded assistant message). */
|
|
95
|
-
function SessionModelBadge({ useProjection, t }) {
|
|
96
|
-
const value = useProjection("perMessageModel");
|
|
97
|
-
const current = value === void 0 || value === null || typeof value !== "object" || value.current === void 0
|
|
98
|
-
? void 0
|
|
99
|
-
: value.current;
|
|
100
|
-
return modelBadge(current, t);
|
|
101
|
-
}
|
|
102
|
-
/** Assistant-actions occupant: per-message model icon, keyed by messageId
|
|
103
|
-
* (renders inside the official per-message action row, reordered after the
|
|
104
|
-
* branch button and before the time clock via CSS flex order). */
|
|
105
|
-
function PerMessageModelBadge({ messageId, useProjection, t }) {
|
|
106
|
-
const value = useProjection("perMessageModel");
|
|
107
|
-
const entry = value === void 0 || value === null || typeof value !== "object" || value.messages === void 0
|
|
108
|
-
? void 0
|
|
109
|
-
: value.messages[messageId];
|
|
110
|
-
return modelBadge(entry, t);
|
|
111
|
-
}
|
|
112
70
|
//#endregion
|
|
113
71
|
//#region client footer
|
|
114
72
|
/**
|
|
@@ -118,26 +76,37 @@ window.__ModuleLoader__.load({
|
|
|
118
76
|
* existing chip behavior (color change + title); a single click rolls the
|
|
119
77
|
* model name out from left to right like a scroll (icon rotates by a random
|
|
120
78
|
* angle); clicking again rolls it back (icon rotates back).
|
|
79
|
+
*
|
|
80
|
+
* Implemented WITHOUT React state on purpose: the DSH slot renderer mounts
|
|
81
|
+
* registrants through an error boundary and some hosts do not tolerate
|
|
82
|
+
* hook-based state in dock seats; the unfold/collapse is a pure DOM class
|
|
83
|
+
* toggle plus an inline transform on the icon, so it works in any host.
|
|
121
84
|
*/
|
|
122
85
|
function FooterModelBadge({ useProjection, t }) {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
const
|
|
126
|
-
const current =
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
const
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
86
|
+
let value = null;
|
|
87
|
+
try { value = useProjection("perMessageModel"); } catch (err) { value = null; }
|
|
88
|
+
const hasValue = value !== null && value !== void 0 && typeof value === "object";
|
|
89
|
+
const current = hasValue && typeof value.current === "object" && value.current !== null ? value.current : null;
|
|
90
|
+
const provider = current !== null && typeof current.provider === "string" ? current.provider : null;
|
|
91
|
+
const model = current !== null && typeof current.model === "string" ? current.model : null;
|
|
92
|
+
let label;
|
|
93
|
+
try { label = provider !== null && model !== null ? provider + " / " + model : (typeof t === "function" ? t("badge.unknown") : "model unknown"); }
|
|
94
|
+
catch (err) { label = provider !== null && model !== null ? provider + " / " + model : "model unknown"; }
|
|
95
|
+
const toggle = (event) => {
|
|
96
|
+
const btn = event && event.currentTarget ? event.currentTarget : null;
|
|
97
|
+
if (btn === null) return;
|
|
98
|
+
const labelEl = btn.querySelector('[class*="footer-label"]');
|
|
99
|
+
const iconEl = btn.querySelector('[class*="footer-icon"]');
|
|
100
|
+
const isOpen = btn.getAttribute("aria-expanded") === "true";
|
|
101
|
+
if (isOpen) {
|
|
102
|
+
btn.setAttribute("aria-expanded", "false");
|
|
103
|
+
if (labelEl !== null) labelEl.setAttribute("data-open", "false");
|
|
104
|
+
if (iconEl !== null) iconEl.style.transform = "rotate(0deg)";
|
|
138
105
|
} else {
|
|
139
|
-
|
|
140
|
-
|
|
106
|
+
const deg = Math.round(90 + Math.random() * 180);
|
|
107
|
+
btn.setAttribute("aria-expanded", "true");
|
|
108
|
+
if (labelEl !== null) labelEl.setAttribute("data-open", "true");
|
|
109
|
+
if (iconEl !== null) iconEl.style.transform = "rotate(" + deg + "deg)";
|
|
141
110
|
}
|
|
142
111
|
};
|
|
143
112
|
return createElement("button", {
|
|
@@ -146,22 +115,22 @@ window.__ModuleLoader__.load({
|
|
|
146
115
|
"data-dsh-per-message-model-footer": "true",
|
|
147
116
|
"aria-label": label,
|
|
148
117
|
title: label,
|
|
149
|
-
"aria-expanded":
|
|
118
|
+
"aria-expanded": "false",
|
|
150
119
|
onClick: toggle
|
|
151
120
|
}, [
|
|
152
121
|
createElement("span", {
|
|
153
122
|
key: "icon",
|
|
154
123
|
className: BADGE_PREFIX + "footer-icon",
|
|
155
|
-
style: { transform:
|
|
124
|
+
style: { transform: "rotate(0deg)" }
|
|
156
125
|
}, chipIcon()),
|
|
157
126
|
createElement("span", {
|
|
158
127
|
key: "label",
|
|
159
128
|
className: BADGE_PREFIX + "footer-label",
|
|
160
|
-
"data-open":
|
|
129
|
+
"data-open": "false"
|
|
161
130
|
}, label)
|
|
162
131
|
]);
|
|
163
132
|
}
|
|
164
|
-
//#endregion
|
|
133
|
+
//#endregion //#endregion
|
|
165
134
|
//#region client divider
|
|
166
135
|
/** Fixed Chinese copy for the model-switch divider (user-required). */
|
|
167
136
|
const SWITCH_COPY = "模型切换:";
|
|
@@ -293,12 +262,7 @@ window.__ModuleLoader__.load({
|
|
|
293
262
|
const badgeStyle = document.createElement("style");
|
|
294
263
|
badgeStyle.dataset.dshPerMessageModel = BADGE_PREFIX;
|
|
295
264
|
badgeStyle.textContent = [
|
|
296
|
-
|
|
297
|
-
`[data-dsh-per-message-model]{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;margin:0 2px;color:var(--dsw-alias-label-tertiary);border-radius:5px;cursor:default}`,
|
|
298
|
-
`[data-dsh-per-message-model]:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-base-2, var(--dsw-alias-bg-hover, rgba(128,128,128,.12)))}`,
|
|
299
|
-
// Reorder inside the official action row: copy(0) branch(0) icon(3) clock(4)
|
|
300
|
-
`[data-dsh-per-message-model]{order:3}`,
|
|
301
|
-
`div[class*="actions"]:has([data-slot="conversation.chat.assistant-actions"]) [class*="timeEnd"]{order:4}`,
|
|
265
|
+
|
|
302
266
|
// In-stream divider: full-width block, embeds in the message flow.
|
|
303
267
|
// Label (模型切换:) and arrow are gray; model names are darker/bolder.
|
|
304
268
|
`[data-dsh-model-switch]{display:flex;align-items:center;gap:8px;margin:10px 0 16px;padding:10px 14px;border:1.5px solid var(--dsw-alias-state-business-primary, #4f8cff);border-radius:10px;background:var(--dsw-alias-state-business-tertiary, rgba(79,140,255,.12));box-shadow:0 1px 3px rgba(0,0,0,.10);color:var(--dsw-alias-label-secondary);font-size:12px;line-height:18px;user-select:none}`,
|
|
@@ -315,18 +279,6 @@ window.__ModuleLoader__.load({
|
|
|
315
279
|
document.head.appendChild(badgeStyle);
|
|
316
280
|
ctx.effect(() => () => badgeStyle.remove(), "per-message-model: css");
|
|
317
281
|
ctx.effect(() => ctx.locale.register(NS, { zh, en }), "per-message-model: dictionaries");
|
|
318
|
-
ctx.slots.inject("conversation.session.header.actions", () => ctx.slots.register({
|
|
319
|
-
name: "conversation.session.header.actions",
|
|
320
|
-
id: "dsh-per-message-model-header",
|
|
321
|
-
locale: NS,
|
|
322
|
-
order: 80
|
|
323
|
-
}, SessionModelBadge));
|
|
324
|
-
ctx.slots.inject("conversation.chat.assistant-actions", () => ctx.slots.register({
|
|
325
|
-
name: "conversation.chat.assistant-actions",
|
|
326
|
-
id: "dsh-per-message-model-badge",
|
|
327
|
-
locale: NS,
|
|
328
|
-
order: 40
|
|
329
|
-
}, PerMessageModelBadge));
|
|
330
282
|
ctx.slots.inject("conversation.session.header.actions", () => ctx.slots.register({
|
|
331
283
|
name: "conversation.session.header.actions",
|
|
332
284
|
id: "dsh-per-message-model-switch",
|