@megen-lebar/dsh-reasoning-effort 0.2.0
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.md +33 -0
- package/cordis.patch.yml +8 -0
- package/lib/client.js +1228 -0
- package/lib/index.js +565 -0
- package/lib/official-levels.json +8430 -0
- package/package.json +30 -0
- package/test/index.test.mjs +79 -0
package/lib/client.js
ADDED
|
@@ -0,0 +1,1228 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dsh-reasoning-effort - browser half.
|
|
3
|
+
*
|
|
4
|
+
* A compact two-step configurator for reasoning levels. The UI intentionally
|
|
5
|
+
* keeps model selection and editing separate so a long provider catalog stays
|
|
6
|
+
* easy to scan and save feedback cannot disappear during a rerender.
|
|
7
|
+
*/
|
|
8
|
+
window.__ModuleLoader__.load({
|
|
9
|
+
id: "@megen-lebar/dsh-reasoning-effort",
|
|
10
|
+
factory: (require) => {
|
|
11
|
+
var module = { exports: {} };
|
|
12
|
+
var exports = module.exports;
|
|
13
|
+
|
|
14
|
+
var NS = "dsh-reasoning-effort";
|
|
15
|
+
var PANEL_ID = "reasoning";
|
|
16
|
+
var PANEL_EVENT = "dsh:sidebar-panel-open";
|
|
17
|
+
var API = "/api/dsh-reasoning";
|
|
18
|
+
var LEVELS = ["off", "minimal", "low", "medium", "high", "xhigh", "max"];
|
|
19
|
+
var LEVEL_LABELS = {
|
|
20
|
+
minimal: "极简",
|
|
21
|
+
low: "低",
|
|
22
|
+
medium: "中",
|
|
23
|
+
high: "高",
|
|
24
|
+
xhigh: "超高",
|
|
25
|
+
max: "最大",
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
var icons = {
|
|
29
|
+
brain: '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M9.5 4.5A3.5 3.5 0 0 0 3 6.3a3.6 3.6 0 0 0-.8 5.9A3.6 3.6 0 0 0 5.7 18c1.5 0 2.8-.9 3.8-2.1V4.5Z"/><path d="M14.5 4.5A3.5 3.5 0 0 1 21 6.3a3.6 3.6 0 0 1 .8 5.9 3.6 3.6 0 0 1-3.5 5.8c-1.5 0-2.8-.9-3.8-2.1V4.5Z"/><path d="M5.8 9.2c1.4.1 2.4.9 2.8 2.2M18.2 9.2c-1.4.1-2.4.9-2.8 2.2"/></svg>',
|
|
30
|
+
close: '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="m6 6 12 12M18 6 6 18"/></svg>',
|
|
31
|
+
back: '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="m15 18-6-6 6-6"/></svg>',
|
|
32
|
+
refresh: '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M20 12a8 8 0 1 1-2.3-5.7L20 8"/><path d="M20 3v5h-5"/></svg>',
|
|
33
|
+
chevron: '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="m9 18 6-6-6-6"/></svg>',
|
|
34
|
+
check: '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12 4 4L19 6"/></svg>',
|
|
35
|
+
info: '<svg viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="9"/><path d="M12 11v5M12 8h.01"/></svg>',
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
function el(tag, attrs, children) {
|
|
39
|
+
var node = document.createElement(tag);
|
|
40
|
+
if (attrs) for (var key in attrs) {
|
|
41
|
+
var value = attrs[key];
|
|
42
|
+
if (key === "class") node.className = value;
|
|
43
|
+
else if (key === "text") node.textContent = value;
|
|
44
|
+
else if (key === "html") node.innerHTML = value;
|
|
45
|
+
else if (key === "onclick") node.addEventListener("click", value);
|
|
46
|
+
else if (key === "onchange") node.addEventListener("change", value);
|
|
47
|
+
else if (key === "oninput") node.addEventListener("input", value);
|
|
48
|
+
else if (key === "checked") node.checked = !!value;
|
|
49
|
+
else if (key === "disabled") node.disabled = !!value;
|
|
50
|
+
else if (key === "value") node.value = value == null ? "" : value;
|
|
51
|
+
else node.setAttribute(key, value);
|
|
52
|
+
}
|
|
53
|
+
if (children) for (var i = 0; i < children.length; i++) {
|
|
54
|
+
if (children[i]) node.appendChild(children[i]);
|
|
55
|
+
}
|
|
56
|
+
// Select values only resolve after their option children exist.
|
|
57
|
+
if (attrs && Object.prototype.hasOwnProperty.call(attrs, "value")) node.value = attrs.value == null ? "" : attrs.value;
|
|
58
|
+
return node;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function iconButton(icon, title, onclick, disabled) {
|
|
62
|
+
return el("button", {
|
|
63
|
+
type: "button",
|
|
64
|
+
title: title,
|
|
65
|
+
"aria-label": title,
|
|
66
|
+
"data-dsh-reasoning-icon-btn": "",
|
|
67
|
+
html: icon,
|
|
68
|
+
onclick: onclick,
|
|
69
|
+
disabled: !!disabled,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function cssText() {
|
|
74
|
+
return [
|
|
75
|
+
'[data-dsh-reasoning-entry]{width:100%;height:32px;box-sizing:border-box;color:var(--dsw-alias-label-secondary);cursor:pointer;white-space:nowrap;background:transparent;border:0;outline:0;border-radius:8px;align-items:center;justify-content:flex-start;text-align:left;margin:0;gap:8px;padding:0 12px;font-size:13px;display:flex;flex:0 0 auto;max-width:100%;overflow:hidden;font-family:inherit}',
|
|
76
|
+
'[data-dsh-reasoning-entry] svg{flex:none;width:14px;height:14px;fill:none;stroke:currentColor;stroke-width:1.6;stroke-linecap:round;stroke-linejoin:round}',
|
|
77
|
+
'[data-dsh-reasoning-entry]:focus-visible{outline:2px solid var(--dsw-alias-border-l3);outline-offset:-2px}',
|
|
78
|
+
'[data-dsh-reasoning-entry]:hover{background:var(--dsw-specific-sidebar-nav-item-hover);color:var(--dsw-alias-label-primary)}',
|
|
79
|
+
'[data-dsh-reasoning-entry][data-active]{background:var(--dsw-specific-sidebar-nav-item-active);color:var(--dsw-alias-label-primary);font-weight:600}',
|
|
80
|
+
'[data-dsh-frame][data-sidebar-collapsed] [data-dsh-reasoning-entry]{justify-content:center;width:100%;padding:0}',
|
|
81
|
+
'[data-dsh-frame][data-sidebar-collapsed] [data-dsh-reasoning-entry] .alabel{display:none}',
|
|
82
|
+
'[data-dsh-reasoning-view]{--re-accent:#2563eb;--re-accent-soft:rgba(37,99,235,.1);--re-success:#16835b;--re-danger:#c13c44;z-index:10000;display:none;position:fixed;left:-100000px;top:0;width:420px;height:0;max-width:calc(100vw - 16px);box-sizing:border-box;flex-direction:column;background:rgba(250,251,252,.98);backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px);border:1px solid var(--dsw-alias-border-l1);border-radius:8px;box-shadow:var(--dsw-shadow-lv3);overflow:hidden;overscroll-behavior:contain;color:var(--dsw-alias-label-primary);font-family:inherit;isolation:isolate}',
|
|
83
|
+
'[data-dsh-reasoning-view][data-open]{display:flex}',
|
|
84
|
+
':root[data-theme=dark] [data-dsh-reasoning-view]{--re-accent:#60a5fa;--re-accent-soft:rgba(96,165,250,.12);--re-success:#49b889;--re-danger:#f07178;background:rgba(24,25,28,.98)}',
|
|
85
|
+
'@media(prefers-color-scheme:dark){:root:not([data-theme=light]) [data-dsh-reasoning-view]{--re-accent:#60a5fa;--re-accent-soft:rgba(96,165,250,.12);--re-success:#49b889;--re-danger:#f07178;background:rgba(24,25,28,.98)}}',
|
|
86
|
+
'[data-dsh-reasoning-header]{flex:none;display:flex;align-items:center;gap:10px;min-height:58px;padding:0 16px;border-bottom:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1)}',
|
|
87
|
+
'[data-dsh-reasoning-mark]{width:30px;height:30px;display:grid;place-items:center;border-radius:7px;background:var(--re-accent-soft);color:var(--re-accent)}',
|
|
88
|
+
'[data-dsh-reasoning-mark] svg{width:18px;height:18px;fill:none;stroke:currentColor;stroke-width:1.6;stroke-linecap:round;stroke-linejoin:round}',
|
|
89
|
+
'[data-dsh-reasoning-heading]{flex:1;min-width:0}',
|
|
90
|
+
'[data-dsh-reasoning-title]{font-size:15px;font-weight:700;line-height:20px}',
|
|
91
|
+
'[data-dsh-reasoning-subtitle]{font-size:11px;color:var(--dsw-alias-label-tertiary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}',
|
|
92
|
+
'[data-dsh-reasoning-icon-btn]{width:32px;height:32px;display:grid;place-items:center;flex:none;border:0;border-radius:7px;background:transparent;color:var(--dsw-alias-label-secondary);cursor:pointer}',
|
|
93
|
+
'[data-dsh-reasoning-icon-btn]:hover{background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary)}',
|
|
94
|
+
'[data-dsh-reasoning-icon-btn]:disabled{opacity:.45;cursor:default}',
|
|
95
|
+
'[data-dsh-reasoning-icon-btn] svg{width:17px;height:17px;fill:none;stroke:currentColor;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}',
|
|
96
|
+
'[data-dsh-reasoning-icon-btn][data-loading] svg{animation:dsh-reasoning-spin .8s linear infinite}',
|
|
97
|
+
'@keyframes dsh-reasoning-spin{to{transform:rotate(360deg)}}',
|
|
98
|
+
'[data-dsh-reasoning-scroll]{flex:1;min-height:0;overflow:auto;overscroll-behavior:contain}',
|
|
99
|
+
'[data-dsh-reasoning-body]{display:flex;flex-direction:column;gap:14px;padding:16px 16px 24px}',
|
|
100
|
+
'[data-dsh-reasoning-toolbar]{display:grid;grid-template-columns:minmax(0,1fr) 32px;gap:8px}',
|
|
101
|
+
'[data-dsh-reasoning-select],[data-dsh-reasoning-search],[data-dsh-reasoning-wire]{box-sizing:border-box;height:34px;border:1px solid var(--dsw-alias-border-l1);border-radius:7px;background:var(--dsw-alias-bg-base);color:var(--dsw-alias-label-primary);font:inherit;font-size:12px;outline:none}',
|
|
102
|
+
'[data-dsh-reasoning-select]{width:100%;padding:0 30px 0 10px}',
|
|
103
|
+
'[data-dsh-reasoning-search]{width:100%;padding:0 10px}',
|
|
104
|
+
'[data-dsh-reasoning-search-empty]{display:none;padding:24px 12px;text-align:center;font-size:11px;color:var(--dsw-alias-label-tertiary)}',
|
|
105
|
+
'[data-dsh-reasoning-search-empty][data-visible]{display:block}',
|
|
106
|
+
'[data-dsh-reasoning-wire]{width:132px;padding:0 9px;font-family:ui-monospace,SFMono-Regular,Consolas,monospace}',
|
|
107
|
+
'[data-dsh-reasoning-wire]:disabled{opacity:.48;background:var(--dsw-alias-bg-layer-2)}',
|
|
108
|
+
'[data-dsh-reasoning-select]:focus,[data-dsh-reasoning-search]:focus,[data-dsh-reasoning-wire]:focus{border-color:var(--re-accent);box-shadow:0 0 0 2px var(--re-accent-soft)}',
|
|
109
|
+
'[data-dsh-reasoning-summary]{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;padding-bottom:12px;border-bottom:1px solid var(--dsw-alias-border-l1)}',
|
|
110
|
+
'[data-dsh-reasoning-summary-title]{font-size:13px;font-weight:650}',
|
|
111
|
+
'[data-dsh-reasoning-summary-copy]{margin-top:2px;font-size:11px;line-height:16px;color:var(--dsw-alias-label-tertiary)}',
|
|
112
|
+
'[data-dsh-reasoning-source]{flex:none;font-size:10px;color:var(--re-success);padding-top:2px}',
|
|
113
|
+
'[data-dsh-reasoning-conversation]{display:flex;align-items:center;gap:10px;padding:10px 11px;border:1px solid var(--dsw-alias-border-l1);border-radius:8px;background:var(--re-accent-soft)}',
|
|
114
|
+
'[data-dsh-reasoning-conversation][data-off]{border-color:var(--re-danger);background:rgba(193,60,68,.08)}',
|
|
115
|
+
'[data-dsh-reasoning-conversation-copy]{flex:1;min-width:0}',
|
|
116
|
+
'[data-dsh-reasoning-conversation-title]{font-size:11px;font-weight:700}',
|
|
117
|
+
'[data-dsh-reasoning-conversation-identity]{margin-top:2px;font-size:10px;line-height:15px;color:var(--dsw-alias-label-secondary);overflow-wrap:anywhere}',
|
|
118
|
+
'[data-dsh-reasoning-conversation-state]{flex:none;font-size:10px;color:var(--re-success);white-space:nowrap}',
|
|
119
|
+
'[data-dsh-reasoning-conversation][data-off] [data-dsh-reasoning-conversation-state]{color:var(--re-danger)}',
|
|
120
|
+
'[data-dsh-reasoning-model-list]{display:flex;flex-direction:column;gap:8px}',
|
|
121
|
+
'[data-dsh-reasoning-model]{width:100%;min-height:68px;display:grid;grid-template-columns:minmax(0,1fr) 22px;align-items:center;gap:10px;padding:10px 12px;text-align:left;border:1px solid var(--dsw-alias-border-l1);border-radius:8px;background:var(--dsw-alias-bg-layer-1);color:inherit;font:inherit;cursor:pointer}',
|
|
122
|
+
'[data-dsh-reasoning-model]:hover{border-color:var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2)}',
|
|
123
|
+
'[data-dsh-reasoning-model][data-current]{border-color:var(--re-accent);background:var(--re-accent-soft)}',
|
|
124
|
+
'[data-dsh-reasoning-model-name]{font-size:13px;font-weight:650;overflow-wrap:anywhere}',
|
|
125
|
+
'[data-dsh-reasoning-model-id]{margin-top:2px;font-size:10px;color:var(--dsw-alias-label-tertiary);overflow-wrap:anywhere}',
|
|
126
|
+
'[data-dsh-reasoning-model-meta]{display:flex;flex-wrap:wrap;gap:8px;margin-top:7px;font-size:10px;color:var(--dsw-alias-label-secondary)}',
|
|
127
|
+
'[data-dsh-reasoning-model-meta] [data-configured]{color:var(--re-success)}',
|
|
128
|
+
'[data-dsh-reasoning-model-meta] [data-off]{color:var(--re-danger)}',
|
|
129
|
+
'[data-dsh-reasoning-model-meta] [data-current]{color:var(--re-accent);font-weight:700}',
|
|
130
|
+
'[data-dsh-reasoning-model] [data-chevron] svg{width:16px;height:16px;fill:none;stroke:var(--dsw-alias-label-tertiary);stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}',
|
|
131
|
+
'[data-dsh-reasoning-empty]{display:flex;flex-direction:column;align-items:center;gap:6px;padding:42px 16px;text-align:center;color:var(--dsw-alias-label-tertiary);font-size:12px}',
|
|
132
|
+
'[data-dsh-reasoning-empty] svg{width:24px;height:24px;fill:none;stroke:currentColor;stroke-width:1.5}',
|
|
133
|
+
'[data-dsh-reasoning-editor-head]{display:flex;align-items:flex-start;gap:10px}',
|
|
134
|
+
'[data-dsh-reasoning-editor-copy]{flex:1;min-width:0}',
|
|
135
|
+
'[data-dsh-reasoning-editor-name]{font-size:15px;font-weight:700;overflow-wrap:anywhere}',
|
|
136
|
+
'[data-dsh-reasoning-editor-id]{margin-top:2px;font-size:10px;color:var(--dsw-alias-label-tertiary);overflow-wrap:anywhere}',
|
|
137
|
+
'[data-dsh-reasoning-section]{display:flex;flex-direction:column;gap:8px;padding-top:2px}',
|
|
138
|
+
'[data-dsh-reasoning-section]+[data-dsh-reasoning-section]{padding-top:14px;border-top:1px solid var(--dsw-alias-border-l1)}',
|
|
139
|
+
'[data-dsh-reasoning-section-head]{display:flex;align-items:center;justify-content:space-between;gap:10px}',
|
|
140
|
+
'[data-dsh-reasoning-section-title]{font-size:12px;font-weight:700}',
|
|
141
|
+
'[data-dsh-reasoning-section-note]{font-size:10px;color:var(--dsw-alias-label-tertiary)}',
|
|
142
|
+
'[data-dsh-reasoning-quick]{display:flex;flex-wrap:wrap;gap:7px}',
|
|
143
|
+
'[data-dsh-reasoning-level]{display:grid;grid-template-columns:22px minmax(74px,1fr) 132px;align-items:center;gap:8px;min-height:44px;padding:6px 8px;border:1px solid var(--dsw-alias-border-l1);border-radius:7px;background:var(--dsw-alias-bg-base)}',
|
|
144
|
+
'[data-dsh-reasoning-level]:hover{background:var(--dsw-alias-bg-layer-1)}',
|
|
145
|
+
'[data-dsh-reasoning-level][data-active]{border-color:var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1)}',
|
|
146
|
+
'[data-dsh-reasoning-level] input[type=checkbox]{width:16px;height:16px;margin:0;accent-color:var(--re-accent)}',
|
|
147
|
+
'[data-dsh-reasoning-level]>label{min-width:0;cursor:pointer}',
|
|
148
|
+
'[data-dsh-reasoning-level-name]{font-size:12px;font-weight:650}',
|
|
149
|
+
'[data-dsh-reasoning-level-detail]{margin-top:1px;font-size:9px;color:var(--dsw-alias-label-tertiary)}',
|
|
150
|
+
'[data-dsh-reasoning-off]{display:grid;grid-template-columns:40px minmax(74px,1fr) auto;align-items:center;gap:8px;min-height:52px;padding:8px 10px;border:1px solid var(--dsw-alias-border-l1);border-radius:7px;background:var(--dsw-alias-bg-base)}',
|
|
151
|
+
'[data-dsh-reasoning-off]:hover{background:var(--dsw-alias-bg-layer-1)}',
|
|
152
|
+
'[data-dsh-reasoning-off][data-active]{border-color:var(--re-danger);background:rgba(193,60,68,.08)}',
|
|
153
|
+
'[data-dsh-reasoning-off] input[type=checkbox]{appearance:none;position:relative;width:38px;height:22px;margin:0;border:1px solid var(--dsw-alias-border-l2);border-radius:999px;background:var(--dsw-alias-bg-layer-2);cursor:pointer;transition:background .16s ease,border-color .16s ease}',
|
|
154
|
+
'[data-dsh-reasoning-off] input[type=checkbox]:after{content:"";position:absolute;top:3px;left:3px;width:14px;height:14px;border-radius:50%;background:var(--dsw-alias-label-tertiary);transition:transform .16s ease,background .16s ease}',
|
|
155
|
+
'[data-dsh-reasoning-off] input[type=checkbox]:checked{border-color:var(--re-danger);background:var(--re-danger)}',
|
|
156
|
+
'[data-dsh-reasoning-off] input[type=checkbox]:checked:after{transform:translateX(16px);background:#fff}',
|
|
157
|
+
'[data-dsh-reasoning-off] input[type=checkbox]:focus-visible{outline:2px solid var(--re-accent);outline-offset:2px}',
|
|
158
|
+
'[data-dsh-reasoning-off]>label{min-width:0;cursor:pointer}',
|
|
159
|
+
'[data-dsh-reasoning-off-state]{flex:none;font-family:ui-monospace,SFMono-Regular,Consolas,monospace;font-size:10px;font-weight:700;padding:2px 7px;border-radius:5px;color:var(--dsw-alias-label-tertiary);background:var(--dsw-alias-bg-layer-2)}',
|
|
160
|
+
'[data-dsh-reasoning-off][data-active] [data-dsh-reasoning-off-state]{color:#fff;background:var(--re-danger)}',
|
|
161
|
+
'[data-dsh-reasoning-off-callout]{padding:10px 11px;border:1px solid rgba(193,60,68,.32);border-radius:7px;background:rgba(193,60,68,.06)}',
|
|
162
|
+
'[data-dsh-reasoning-off-callout-title]{font-size:12px;font-weight:700;color:var(--re-danger)}',
|
|
163
|
+
'[data-dsh-reasoning-off-callout-copy],[data-dsh-reasoning-scope-note]{margin-top:3px;font-size:10px;line-height:16px;color:var(--dsw-alias-label-secondary);overflow-wrap:anywhere}',
|
|
164
|
+
'[data-dsh-reasoning-scope-note]{padding:0 2px}',
|
|
165
|
+
'[data-dsh-reasoning-form]{display:grid;grid-template-columns:minmax(0,1fr) minmax(150px,190px);align-items:center;gap:9px 12px}',
|
|
166
|
+
'[data-dsh-reasoning-label]{font-size:11px;color:var(--dsw-alias-label-secondary)}',
|
|
167
|
+
'[data-dsh-reasoning-btn]{min-height:32px;box-sizing:border-box;border-radius:7px;padding:0 12px;border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);font:inherit;font-size:12px;cursor:pointer}',
|
|
168
|
+
'[data-dsh-reasoning-btn]:hover{background:var(--dsw-alias-bg-layer-2)}',
|
|
169
|
+
'[data-dsh-reasoning-btn=primary]{min-width:82px;border-color:var(--re-accent);background:var(--re-accent);color:#fff;font-weight:650}',
|
|
170
|
+
'[data-dsh-reasoning-btn=primary]:hover{filter:brightness(.96)}',
|
|
171
|
+
'[data-dsh-reasoning-btn]:disabled{opacity:.48;cursor:default;filter:none}',
|
|
172
|
+
'[data-dsh-reasoning-actions]{position:sticky;bottom:0;z-index:2;display:flex;align-items:center;gap:8px;padding:11px 16px;border-top:1px solid var(--dsw-alias-border-l1);background:rgba(250,251,252,.96);backdrop-filter:blur(12px)}',
|
|
173
|
+
':root[data-theme=dark] [data-dsh-reasoning-actions]{background:rgba(24,25,28,.96)}',
|
|
174
|
+
'@media(prefers-color-scheme:dark){:root:not([data-theme=light]) [data-dsh-reasoning-actions]{background:rgba(24,25,28,.96)}}',
|
|
175
|
+
'[data-dsh-reasoning-save-state]{flex:1;min-width:0;font-size:10px;color:var(--dsw-alias-label-tertiary);overflow-wrap:anywhere}',
|
|
176
|
+
'[data-dsh-reasoning-notice]{flex:none;display:flex;align-items:flex-start;gap:8px;margin:10px 16px 0;padding:9px 11px;border:1px solid var(--dsw-alias-border-l2);border-radius:7px;background:var(--dsw-alias-bg-layer-1);font-size:11px;line-height:16px;color:var(--dsw-alias-label-secondary)}',
|
|
177
|
+
'[data-dsh-reasoning-notice] svg{width:14px;height:14px;flex:none;margin-top:1px;fill:none;stroke:currentColor;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}',
|
|
178
|
+
'[data-dsh-reasoning-notice=success]{border-left-color:var(--re-success);color:var(--re-success)}',
|
|
179
|
+
'[data-dsh-reasoning-notice=error]{border-left-color:var(--re-danger);color:var(--re-danger)}',
|
|
180
|
+
'[data-dsh-reasoning-confirm]{display:flex;align-items:center;gap:8px;width:100%}',
|
|
181
|
+
'[data-dsh-reasoning-confirm-copy]{flex:1;min-width:0;font-size:10px;color:var(--re-danger)}',
|
|
182
|
+
'@media(max-width:560px){[data-dsh-reasoning-view]{border-radius:0;max-width:100vw}[data-dsh-reasoning-body]{padding:14px 12px 36px}[data-dsh-reasoning-conversation]{align-items:flex-start;flex-wrap:wrap}[data-dsh-reasoning-level]{grid-template-columns:22px minmax(66px,1fr) minmax(100px,128px)}[data-dsh-reasoning-wire]{width:100%}[data-dsh-reasoning-form]{grid-template-columns:1fr}[data-dsh-reasoning-actions]{padding:10px 12px}}',
|
|
183
|
+
].join("\n");
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function injectCss() {
|
|
187
|
+
var current = document.getElementById("dsh-reasoning-effort-css");
|
|
188
|
+
if (current) current.remove();
|
|
189
|
+
var style = document.createElement("style");
|
|
190
|
+
style.id = "dsh-reasoning-effort-css";
|
|
191
|
+
style.textContent = cssText();
|
|
192
|
+
document.head.appendChild(style);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function sidebarRoot() {
|
|
196
|
+
var column = document.querySelector('[data-pane="sidebar"], [class*="sidebarCol"]');
|
|
197
|
+
if (!column) return undefined;
|
|
198
|
+
return column.querySelector('[class*="logoRow"]')?.parentElement ?? column.firstElementChild;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function newSessionButton(root) {
|
|
202
|
+
var nested = root?.querySelector('button[class*="newSession"]');
|
|
203
|
+
if (nested) return nested;
|
|
204
|
+
if (root) for (var i = 0; i < root.children.length; i++) {
|
|
205
|
+
if (root.children[i].tagName === "BUTTON") return root.children[i];
|
|
206
|
+
}
|
|
207
|
+
return undefined;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
var state = {
|
|
211
|
+
open: false,
|
|
212
|
+
loading: false,
|
|
213
|
+
saving: false,
|
|
214
|
+
error: null,
|
|
215
|
+
list: null,
|
|
216
|
+
providerId: null,
|
|
217
|
+
providerPinned: false,
|
|
218
|
+
modelIndex: null,
|
|
219
|
+
query: "",
|
|
220
|
+
edit: null,
|
|
221
|
+
notice: null,
|
|
222
|
+
discardConfirm: false,
|
|
223
|
+
conversation: null,
|
|
224
|
+
};
|
|
225
|
+
var listeners = [];
|
|
226
|
+
var noticeTimer;
|
|
227
|
+
var modelDirectories;
|
|
228
|
+
|
|
229
|
+
function publish() {
|
|
230
|
+
for (var i = 0; i < listeners.length; i++) listeners[i]();
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function subscribe(fn) {
|
|
234
|
+
listeners.push(fn);
|
|
235
|
+
return function () { listeners = listeners.filter(function (item) { return item !== fn; }); };
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function setNotice(type, message, sticky) {
|
|
239
|
+
state.notice = { type: type, message: message };
|
|
240
|
+
clearTimeout(noticeTimer);
|
|
241
|
+
if (!sticky) {
|
|
242
|
+
noticeTimer = setTimeout(function () {
|
|
243
|
+
state.notice = null;
|
|
244
|
+
publish();
|
|
245
|
+
}, 3600);
|
|
246
|
+
}
|
|
247
|
+
publish();
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function clearErrorNotice() {
|
|
251
|
+
if (state.notice && state.notice.type === "error") {
|
|
252
|
+
state.notice = null;
|
|
253
|
+
clearTimeout(noticeTimer);
|
|
254
|
+
document.querySelector('[data-dsh-reasoning-notice="error"]')?.remove();
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
function markEdited() {
|
|
259
|
+
clearErrorNotice();
|
|
260
|
+
var wasConfirming = state.discardConfirm;
|
|
261
|
+
state.discardConfirm = false;
|
|
262
|
+
if (wasConfirming) publish();
|
|
263
|
+
else syncEditorControls();
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
async function api(path, body) {
|
|
267
|
+
var response = await fetch(API + path, {
|
|
268
|
+
method: "POST",
|
|
269
|
+
headers: { "content-type": "application/json" },
|
|
270
|
+
body: JSON.stringify(body || {}),
|
|
271
|
+
});
|
|
272
|
+
var payload;
|
|
273
|
+
try {
|
|
274
|
+
payload = await response.json();
|
|
275
|
+
} catch (error) {
|
|
276
|
+
throw new Error("服务返回了无法解析的响应 (HTTP " + response.status + ")");
|
|
277
|
+
}
|
|
278
|
+
if (!response.ok && payload.ok !== false) throw new Error("请求失败 (HTTP " + response.status + ")");
|
|
279
|
+
return payload;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
function selectedProvider() {
|
|
283
|
+
if (!state.list) return undefined;
|
|
284
|
+
for (var i = 0; i < state.list.providers.length; i++) {
|
|
285
|
+
if (state.list.providers[i].id === state.providerId) return state.list.providers[i];
|
|
286
|
+
}
|
|
287
|
+
return undefined;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
function selectedModel() {
|
|
291
|
+
var provider = selectedProvider();
|
|
292
|
+
if (!provider || state.modelIndex === null) return undefined;
|
|
293
|
+
for (var i = 0; i < provider.models.length; i++) {
|
|
294
|
+
if (provider.models[i].index === state.modelIndex) return provider.models[i];
|
|
295
|
+
}
|
|
296
|
+
return undefined;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
function providerById(providerId) {
|
|
300
|
+
if (!state.list || typeof providerId !== "string") return undefined;
|
|
301
|
+
return state.list.providers.find(function (provider) { return provider.id === providerId; });
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
function modelByIdentity(providerId, modelId) {
|
|
305
|
+
var provider = providerById(providerId);
|
|
306
|
+
return provider && provider.models.find(function (model) { return model.id === modelId; });
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
function isConversationModel(providerId, modelId) {
|
|
310
|
+
return !!state.conversation && !state.conversation.ambiguous && state.conversation.provider === providerId && state.conversation.model === modelId;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
function modelIsOff(providerId, modelId) {
|
|
314
|
+
var model = modelByIdentity(providerId, modelId);
|
|
315
|
+
return !!(model && model.current && model.current.reasoningEfforts === false);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
function knownDirectories() {
|
|
319
|
+
var directories = modelDirectories && modelDirectories.live && modelDirectories.live.directories;
|
|
320
|
+
if (!directories || typeof directories.forEach !== "function") return [];
|
|
321
|
+
var result = [];
|
|
322
|
+
directories.forEach(function (directory) {
|
|
323
|
+
if (directory && directory.store && typeof directory.store.getSnapshot === "function") result.push(directory);
|
|
324
|
+
});
|
|
325
|
+
return result;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
async function syncConversation(options) {
|
|
329
|
+
var directories = knownDirectories();
|
|
330
|
+
if (!directories.length) {
|
|
331
|
+
state.conversation = null;
|
|
332
|
+
return null;
|
|
333
|
+
}
|
|
334
|
+
if (options && options.reload) {
|
|
335
|
+
await Promise.all(directories.map(function (directory) {
|
|
336
|
+
return Promise.resolve(directory.load()).catch(function () { return undefined; });
|
|
337
|
+
}));
|
|
338
|
+
}
|
|
339
|
+
var selections = [];
|
|
340
|
+
var seen = {};
|
|
341
|
+
for (var i = 0; i < directories.length; i++) {
|
|
342
|
+
var current = directories[i].store.getSnapshot()?.current;
|
|
343
|
+
if (!current || typeof current.provider !== "string" || typeof current.model !== "string") continue;
|
|
344
|
+
var key = current.provider + "\u0000" + current.model;
|
|
345
|
+
if (seen[key]) continue;
|
|
346
|
+
seen[key] = true;
|
|
347
|
+
selections.push({ provider: current.provider, model: current.model, reasoningEffort: current.reasoningEffort });
|
|
348
|
+
}
|
|
349
|
+
state.conversation = selections.length === 1 ? selections[0] : (selections.length > 1 ? { ambiguous: true, count: selections.length } : null);
|
|
350
|
+
return state.conversation;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
function focusConversationModel() {
|
|
354
|
+
var conversation = state.conversation;
|
|
355
|
+
if (!conversation || conversation.ambiguous || !providerById(conversation.provider)) return;
|
|
356
|
+
state.providerId = conversation.provider;
|
|
357
|
+
state.providerPinned = true;
|
|
358
|
+
state.query = "";
|
|
359
|
+
state.notice = null;
|
|
360
|
+
publish();
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
async function refresh(options) {
|
|
364
|
+
var quiet = options && options.quiet;
|
|
365
|
+
if (!quiet) state.loading = true;
|
|
366
|
+
state.error = null;
|
|
367
|
+
if (!quiet) publish();
|
|
368
|
+
try {
|
|
369
|
+
var response = await api("/list");
|
|
370
|
+
if (!response.ok) throw new Error(response.error || "加载失败");
|
|
371
|
+
state.list = response.value;
|
|
372
|
+
await syncConversation({ reload: !!(options && options.syncConversation) });
|
|
373
|
+
var providerExists = state.list.providers.some(function (provider) { return provider.id === state.providerId; });
|
|
374
|
+
var conversationProvider = state.conversation && !state.conversation.ambiguous && providerById(state.conversation.provider);
|
|
375
|
+
if ((!state.providerId || !providerExists || !state.providerPinned) && conversationProvider) state.providerId = conversationProvider.id;
|
|
376
|
+
else if (!providerExists) state.providerId = state.list.providers.length ? state.list.providers[0].id : null;
|
|
377
|
+
} catch (error) {
|
|
378
|
+
state.error = error instanceof Error ? error.message : String(error);
|
|
379
|
+
if (state.list) state.notice = { type: "error", message: "刷新失败:" + state.error };
|
|
380
|
+
else state.list = null;
|
|
381
|
+
}
|
|
382
|
+
state.loading = false;
|
|
383
|
+
publish();
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
function popoverView() {
|
|
387
|
+
return document.querySelector("[data-dsh-reasoning-view]");
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
function popoverShown() {
|
|
391
|
+
var view = popoverView();
|
|
392
|
+
if (!view) return false;
|
|
393
|
+
return view.hasAttribute("data-open");
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
function setOpen(open, announce) {
|
|
397
|
+
state.open = open;
|
|
398
|
+
document.documentElement.toggleAttribute("data-dsh-reasoning-active", open);
|
|
399
|
+
if (open && announce !== false) window.dispatchEvent(new CustomEvent(PANEL_EVENT, { detail: { panel: PANEL_ID } }));
|
|
400
|
+
if (open) refresh({ quiet: !!state.list, syncConversation: true });
|
|
401
|
+
publish();
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
function requestClosePanel() {
|
|
405
|
+
if (state.saving) return;
|
|
406
|
+
// Closing the drawer preserves a draft; returning to the model list is
|
|
407
|
+
// the explicit destructive action and gets its own confirmation.
|
|
408
|
+
setOpen(false);
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
function toggle() {
|
|
412
|
+
if (state.open && !popoverShown()) {
|
|
413
|
+
setOpen(false, false);
|
|
414
|
+
setOpen(true);
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
if (state.open) requestClosePanel();
|
|
418
|
+
else setOpen(true);
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
function officialMap(model) {
|
|
422
|
+
var result = {};
|
|
423
|
+
var levels = model && model.official && model.official.levels ? model.official.levels : [];
|
|
424
|
+
for (var i = 0; i < levels.length; i++) result[levels[i].level] = levels[i].wire;
|
|
425
|
+
return result;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
function snapshotEdit(edit) {
|
|
429
|
+
var levels = {};
|
|
430
|
+
for (var i = 1; i < LEVELS.length; i++) {
|
|
431
|
+
var level = LEVELS[i];
|
|
432
|
+
levels[level] = { checked: !!edit.levels[level].checked, wire: edit.levels[level].wire.trim() };
|
|
433
|
+
}
|
|
434
|
+
return JSON.stringify({
|
|
435
|
+
levels: levels,
|
|
436
|
+
off: !!edit.off,
|
|
437
|
+
defaultReasoning: edit.defaultReasoning,
|
|
438
|
+
thinkingFormat: edit.thinkingFormat,
|
|
439
|
+
supportsReasoningEffort: edit.supportsReasoningEffort,
|
|
440
|
+
});
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
function makeEdit(provider, model) {
|
|
444
|
+
var current = model.current && model.current.reasoningEfforts;
|
|
445
|
+
var official = officialMap(model);
|
|
446
|
+
var levels = {};
|
|
447
|
+
for (var i = 1; i < LEVELS.length; i++) {
|
|
448
|
+
var level = LEVELS[i];
|
|
449
|
+
var configured = current && current !== false && Object.prototype.hasOwnProperty.call(current, level) && current[level] != null;
|
|
450
|
+
var followsOfficial = current === undefined && Object.prototype.hasOwnProperty.call(official, level) && official[level] != null;
|
|
451
|
+
var wire = configured ? String(current[level]) : (official[level] == null ? level : String(official[level]));
|
|
452
|
+
levels[level] = { checked: !!configured || followsOfficial, wire: wire };
|
|
453
|
+
}
|
|
454
|
+
var compat = provider.compat || {};
|
|
455
|
+
var edit = {
|
|
456
|
+
levels: levels,
|
|
457
|
+
off: current === false,
|
|
458
|
+
defaultReasoning: current === false ? "" : (provider.reasoning || ""),
|
|
459
|
+
thinkingFormat: compat.thinkingFormat || "",
|
|
460
|
+
supportsReasoningEffort: compat.supportsReasoningEffort === undefined ? "" : String(compat.supportsReasoningEffort),
|
|
461
|
+
initial: "",
|
|
462
|
+
};
|
|
463
|
+
if (current === undefined && model.storage === "models") {
|
|
464
|
+
var persisted = {
|
|
465
|
+
levels: {},
|
|
466
|
+
off: false,
|
|
467
|
+
defaultReasoning: edit.defaultReasoning,
|
|
468
|
+
thinkingFormat: edit.thinkingFormat,
|
|
469
|
+
supportsReasoningEffort: edit.supportsReasoningEffort,
|
|
470
|
+
};
|
|
471
|
+
for (var li = 1; li < LEVELS.length; li++) {
|
|
472
|
+
var persistedLevel = LEVELS[li];
|
|
473
|
+
persisted.levels[persistedLevel] = { checked: false, wire: edit.levels[persistedLevel].wire };
|
|
474
|
+
}
|
|
475
|
+
edit.initial = snapshotEdit(persisted);
|
|
476
|
+
} else {
|
|
477
|
+
edit.initial = snapshotEdit(edit);
|
|
478
|
+
}
|
|
479
|
+
return edit;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
function openEditor(modelIndex) {
|
|
483
|
+
var provider = selectedProvider();
|
|
484
|
+
if (!provider) return;
|
|
485
|
+
var model = provider.models.find(function (item) { return item.index === modelIndex; });
|
|
486
|
+
if (!model) return;
|
|
487
|
+
state.modelIndex = modelIndex;
|
|
488
|
+
state.edit = makeEdit(provider, model);
|
|
489
|
+
state.notice = null;
|
|
490
|
+
state.discardConfirm = false;
|
|
491
|
+
publish();
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
function discardEditor() {
|
|
495
|
+
state.modelIndex = null;
|
|
496
|
+
state.edit = null;
|
|
497
|
+
state.discardConfirm = false;
|
|
498
|
+
state.notice = null;
|
|
499
|
+
publish();
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
function closeEditor() {
|
|
503
|
+
if (state.saving) return;
|
|
504
|
+
if (isDirty()) {
|
|
505
|
+
state.discardConfirm = true;
|
|
506
|
+
publish();
|
|
507
|
+
return;
|
|
508
|
+
}
|
|
509
|
+
discardEditor();
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
function enabledLevels() {
|
|
513
|
+
var levels = [];
|
|
514
|
+
if (!state.edit) return levels;
|
|
515
|
+
for (var i = 1; i < LEVELS.length; i++) {
|
|
516
|
+
if (state.edit.levels[LEVELS[i]].checked) levels.push(LEVELS[i]);
|
|
517
|
+
}
|
|
518
|
+
return levels;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
function isDirty() {
|
|
522
|
+
return !!state.edit && snapshotEdit(state.edit) !== state.edit.initial;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
function syncEditorControls() {
|
|
526
|
+
var save = document.querySelector("[data-dsh-reasoning-save]");
|
|
527
|
+
var status = document.querySelector("[data-dsh-reasoning-save-state]");
|
|
528
|
+
var off = !!(state.edit && state.edit.off);
|
|
529
|
+
if (save) {
|
|
530
|
+
save.disabled = state.saving || !isDirty();
|
|
531
|
+
save.textContent = state.saving ? "同步中..." : (off ? "保存并关闭" : "保存并同步");
|
|
532
|
+
}
|
|
533
|
+
if (status) status.textContent = state.saving ? "正在校验并同步对话模型" : (isDirty() ? (off ? "关闭推理待保存" : "有未保存的修改") : "当前没有修改");
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
function rerenderEditor() {
|
|
537
|
+
var current = document.querySelector("[data-dsh-reasoning-scroll]");
|
|
538
|
+
var scrollTop = current ? current.scrollTop : 0;
|
|
539
|
+
clearErrorNotice();
|
|
540
|
+
state.discardConfirm = false;
|
|
541
|
+
renderPanel();
|
|
542
|
+
var next = document.querySelector("[data-dsh-reasoning-scroll]");
|
|
543
|
+
if (next) next.scrollTop = scrollTop;
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
function applyOfficialLevels(model) {
|
|
547
|
+
if (!model || !state.edit) return false;
|
|
548
|
+
var official = officialMap(model);
|
|
549
|
+
var found = false;
|
|
550
|
+
for (var i = 1; i < LEVELS.length; i++) {
|
|
551
|
+
var level = LEVELS[i];
|
|
552
|
+
var supported = Object.prototype.hasOwnProperty.call(official, level) && official[level] != null;
|
|
553
|
+
state.edit.levels[level].checked = supported;
|
|
554
|
+
if (supported) {
|
|
555
|
+
state.edit.levels[level].wire = String(official[level]);
|
|
556
|
+
found = true;
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
if (state.edit.defaultReasoning && enabledLevels().indexOf(state.edit.defaultReasoning) < 0) state.edit.defaultReasoning = "";
|
|
560
|
+
return found;
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
function applyOfficial() {
|
|
564
|
+
var model = selectedModel();
|
|
565
|
+
if (!model || !state.edit || state.edit.off) return;
|
|
566
|
+
applyOfficialLevels(model);
|
|
567
|
+
rerenderEditor();
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
function restoreCurrent() {
|
|
571
|
+
var provider = selectedProvider();
|
|
572
|
+
var model = selectedModel();
|
|
573
|
+
if (!provider || !model) return;
|
|
574
|
+
state.edit = makeEdit(provider, model);
|
|
575
|
+
rerenderEditor();
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
async function saveEditor() {
|
|
579
|
+
var provider = selectedProvider();
|
|
580
|
+
var model = selectedModel();
|
|
581
|
+
if (!provider || !model || !state.edit || state.saving || !isDirty()) return;
|
|
582
|
+
|
|
583
|
+
var efforts = false;
|
|
584
|
+
var enabled = enabledLevels();
|
|
585
|
+
if (!state.edit.off) {
|
|
586
|
+
if (!enabled.length) {
|
|
587
|
+
setNotice("error", "请至少启用一个推理等级;要关闭推理请使用上方开关。", true);
|
|
588
|
+
return;
|
|
589
|
+
}
|
|
590
|
+
efforts = { off: null };
|
|
591
|
+
for (var i = 0; i < enabled.length; i++) {
|
|
592
|
+
var level = enabled[i];
|
|
593
|
+
var wire = state.edit.levels[level].wire.trim();
|
|
594
|
+
if (!wire) {
|
|
595
|
+
setNotice("error", "“" + LEVEL_LABELS[level] + "”已启用,请填写线上拼写。", true);
|
|
596
|
+
return;
|
|
597
|
+
}
|
|
598
|
+
efforts[level] = wire;
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
if (state.edit.defaultReasoning && state.edit.defaultReasoning !== "off" && enabled.indexOf(state.edit.defaultReasoning) < 0) {
|
|
602
|
+
setNotice("error", "默认强度必须是当前已启用的等级。", true);
|
|
603
|
+
return;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
var savedProvider = provider.id;
|
|
607
|
+
var savedModel = model.id;
|
|
608
|
+
var body = {
|
|
609
|
+
provider: provider.id,
|
|
610
|
+
modelIndex: model.index,
|
|
611
|
+
modelId: model.id,
|
|
612
|
+
storage: model.storage,
|
|
613
|
+
reasoningEfforts: efforts,
|
|
614
|
+
};
|
|
615
|
+
if (!state.edit.off) {
|
|
616
|
+
body.defaultReasoning = state.edit.defaultReasoning;
|
|
617
|
+
body.compat = {
|
|
618
|
+
thinkingFormat: state.edit.thinkingFormat,
|
|
619
|
+
supportsReasoningEffort: state.edit.supportsReasoningEffort === "" ? null : state.edit.supportsReasoningEffort === "true",
|
|
620
|
+
};
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
state.saving = true;
|
|
624
|
+
state.notice = null;
|
|
625
|
+
syncEditorControls();
|
|
626
|
+
try {
|
|
627
|
+
var response = await api("/save-model", body);
|
|
628
|
+
if (!response.ok) throw new Error(response.error || "配置被拒绝");
|
|
629
|
+
state.saving = false;
|
|
630
|
+
state.modelIndex = null;
|
|
631
|
+
state.edit = null;
|
|
632
|
+
await refresh({ quiet: true, syncConversation: true });
|
|
633
|
+
var syncedOff = response.value && response.value.offOnly && isConversationModel(savedProvider, savedModel) && modelIsOff(savedProvider, savedModel);
|
|
634
|
+
setNotice("success", response.value && response.value.offOnly ? (syncedOff ? "已关闭并同步到当前对话:推理等级已隐藏。" : "已关闭该模型的推理;对话模型菜单会在下次打开时刷新。") : "思考强度已保存并同步到对话模型目录。");
|
|
635
|
+
} catch (error) {
|
|
636
|
+
state.saving = false;
|
|
637
|
+
var message = error instanceof Error ? error.message : String(error);
|
|
638
|
+
setNotice("error", "保存失败:" + message, true);
|
|
639
|
+
syncEditorControls();
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
function renderHeader(view) {
|
|
644
|
+
var model = selectedModel();
|
|
645
|
+
var provider = selectedProvider();
|
|
646
|
+
var title = model ? "编辑思考强度" : "思考强度";
|
|
647
|
+
var subtitle = model && provider ? provider.id + " / " + model.id : "与当前对话模型保持同步";
|
|
648
|
+
view.appendChild(el("div", { "data-dsh-reasoning-header": "" }, [
|
|
649
|
+
el("div", { "data-dsh-reasoning-mark": "", html: icons.brain }),
|
|
650
|
+
el("div", { "data-dsh-reasoning-heading": "" }, [
|
|
651
|
+
el("div", { "data-dsh-reasoning-title": "", text: title }),
|
|
652
|
+
el("div", { "data-dsh-reasoning-subtitle": "", text: subtitle }),
|
|
653
|
+
]),
|
|
654
|
+
iconButton(icons.close, "关闭", toggle),
|
|
655
|
+
]));
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
function renderNotice(view) {
|
|
659
|
+
if (!state.notice) return;
|
|
660
|
+
view.appendChild(el("div", {
|
|
661
|
+
"data-dsh-reasoning-notice": state.notice.type,
|
|
662
|
+
role: state.notice.type === "error" ? "alert" : "status",
|
|
663
|
+
}, [
|
|
664
|
+
el("span", { html: state.notice.type === "success" ? icons.check : icons.info }),
|
|
665
|
+
el("span", { text: state.notice.message }),
|
|
666
|
+
]));
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
function renderConversationStatus(body) {
|
|
670
|
+
var conversation = state.conversation;
|
|
671
|
+
if (!conversation || conversation.ambiguous) return;
|
|
672
|
+
var provider = providerById(conversation.provider);
|
|
673
|
+
var model = modelByIdentity(conversation.provider, conversation.model);
|
|
674
|
+
var off = modelIsOff(conversation.provider, conversation.model);
|
|
675
|
+
var attrs = { "data-dsh-reasoning-conversation": "" };
|
|
676
|
+
if (off) attrs["data-off"] = "";
|
|
677
|
+
var identity = (provider ? provider.displayName : conversation.provider) + " / " + (model ? model.name : conversation.model);
|
|
678
|
+
var status = off ? "推理已关闭" : (conversation.reasoningEffort ? "当前强度:" + conversation.reasoningEffort : "跟随模型默认");
|
|
679
|
+
var children = [
|
|
680
|
+
el("div", { "data-dsh-reasoning-conversation-copy": "" }, [
|
|
681
|
+
el("div", { "data-dsh-reasoning-conversation-title": "", text: "当前对话模型" }),
|
|
682
|
+
el("div", { "data-dsh-reasoning-conversation-identity": "", text: identity }),
|
|
683
|
+
]),
|
|
684
|
+
el("div", { "data-dsh-reasoning-conversation-state": "", text: status }),
|
|
685
|
+
];
|
|
686
|
+
if (state.providerId !== conversation.provider) {
|
|
687
|
+
children.push(el("button", { type: "button", "data-dsh-reasoning-btn": "", text: "定位", onclick: focusConversationModel }));
|
|
688
|
+
}
|
|
689
|
+
body.appendChild(el("div", attrs, children));
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
function renderLoading(body) {
|
|
693
|
+
body.appendChild(el("div", { "data-dsh-reasoning-empty": "" }, [
|
|
694
|
+
el("div", { html: icons.refresh }),
|
|
695
|
+
el("div", { text: "正在同步模型配置..." }),
|
|
696
|
+
]));
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
function modelStatus(model) {
|
|
700
|
+
var current = model.current && model.current.reasoningEfforts;
|
|
701
|
+
if (current === false) return "已关闭";
|
|
702
|
+
if (!current) return "跟随模型默认";
|
|
703
|
+
var levels = [];
|
|
704
|
+
for (var i = 1; i < LEVELS.length; i++) if (current[LEVELS[i]] != null) levels.push(LEVELS[i]);
|
|
705
|
+
return levels.length ? levels.join(" · ") : "跟随模型默认";
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
function officialStatus(model) {
|
|
709
|
+
if (!model.official || !model.official.found) return "未匹配官方目录";
|
|
710
|
+
if (!model.official.reasoning) return "官方标记为非推理模型";
|
|
711
|
+
var levels = (model.official.levels || []).filter(function (item) { return item.level !== "off"; });
|
|
712
|
+
return levels.length ? "官方 " + levels.length + " 档" : "官方推理模型";
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
function renderModelList(body) {
|
|
716
|
+
var list = state.list;
|
|
717
|
+
if (!list || !list.providers.length) {
|
|
718
|
+
body.appendChild(el("div", { "data-dsh-reasoning-empty": "" }, [
|
|
719
|
+
el("div", { html: icons.info }),
|
|
720
|
+
el("div", { text: "还没有可配置的 Provider" }),
|
|
721
|
+
]));
|
|
722
|
+
return;
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
var providerOptions = list.providers.map(function (provider) {
|
|
726
|
+
return el("option", { value: provider.id, text: provider.displayName + " · " + provider.id });
|
|
727
|
+
});
|
|
728
|
+
var providerSelect = el("select", {
|
|
729
|
+
"data-dsh-reasoning-select": "",
|
|
730
|
+
"aria-label": "选择 Provider",
|
|
731
|
+
value: state.providerId,
|
|
732
|
+
onchange: function (event) {
|
|
733
|
+
state.providerId = event.target.value;
|
|
734
|
+
state.providerPinned = true;
|
|
735
|
+
state.query = "";
|
|
736
|
+
state.notice = null;
|
|
737
|
+
publish();
|
|
738
|
+
},
|
|
739
|
+
}, providerOptions);
|
|
740
|
+
var refreshButton = iconButton(icons.refresh, state.loading ? "正在同步" : "重新同步", function () { refresh(); }, state.loading);
|
|
741
|
+
if (state.loading) refreshButton.setAttribute("data-loading", "");
|
|
742
|
+
body.appendChild(el("div", { "data-dsh-reasoning-toolbar": "" }, [
|
|
743
|
+
providerSelect,
|
|
744
|
+
refreshButton,
|
|
745
|
+
]));
|
|
746
|
+
renderConversationStatus(body);
|
|
747
|
+
|
|
748
|
+
var provider = selectedProvider();
|
|
749
|
+
if (!provider) return;
|
|
750
|
+
var generated = list.catalogGeneratedAt ? new Date(list.catalogGeneratedAt).toLocaleDateString() : "";
|
|
751
|
+
body.appendChild(el("div", { "data-dsh-reasoning-summary": "" }, [
|
|
752
|
+
el("div", {}, [
|
|
753
|
+
el("div", { "data-dsh-reasoning-summary-title": "", text: provider.displayName }),
|
|
754
|
+
el("div", { "data-dsh-reasoning-summary-copy": "", text: provider.models.length + " 个模型 · " + (provider.api || "自动协议") }),
|
|
755
|
+
]),
|
|
756
|
+
el("div", { "data-dsh-reasoning-source": "", text: list.catalogSource === "runtime" ? "已同步官方目录" + (generated ? " · " + generated : "") : "内置目录" }),
|
|
757
|
+
]));
|
|
758
|
+
|
|
759
|
+
var searchEmpty = el("div", { "data-dsh-reasoning-search-empty": "", text: "没有匹配的模型" });
|
|
760
|
+
function filterRows(query) {
|
|
761
|
+
var needle = query.trim().toLowerCase();
|
|
762
|
+
var rows = document.querySelectorAll("[data-dsh-reasoning-model]");
|
|
763
|
+
var visible = 0;
|
|
764
|
+
for (var ri = 0; ri < rows.length; ri++) {
|
|
765
|
+
var hidden = rows[ri].getAttribute("data-search").indexOf(needle) < 0;
|
|
766
|
+
rows[ri].hidden = hidden;
|
|
767
|
+
if (!hidden) visible++;
|
|
768
|
+
}
|
|
769
|
+
searchEmpty.toggleAttribute("data-visible", visible === 0);
|
|
770
|
+
}
|
|
771
|
+
if (provider.models.length > 6) {
|
|
772
|
+
body.appendChild(el("input", {
|
|
773
|
+
type: "search",
|
|
774
|
+
placeholder: "搜索模型名称或 ID",
|
|
775
|
+
"data-dsh-reasoning-search": "",
|
|
776
|
+
value: state.query,
|
|
777
|
+
oninput: function (event) {
|
|
778
|
+
state.query = event.target.value;
|
|
779
|
+
filterRows(state.query);
|
|
780
|
+
},
|
|
781
|
+
}));
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
var modelList = el("div", { "data-dsh-reasoning-model-list": "" });
|
|
785
|
+
for (var i = 0; i < provider.models.length; i++) {
|
|
786
|
+
(function (model) {
|
|
787
|
+
var current = model.current && model.current.reasoningEfforts;
|
|
788
|
+
var configured = current !== undefined;
|
|
789
|
+
var active = isConversationModel(provider.id, model.id);
|
|
790
|
+
var search = (model.name + " " + model.id).toLowerCase();
|
|
791
|
+
var statusAttrs = { text: modelStatus(model) };
|
|
792
|
+
if (configured) statusAttrs["data-configured"] = "";
|
|
793
|
+
if (current === false) statusAttrs["data-off"] = "";
|
|
794
|
+
var row = el("button", {
|
|
795
|
+
type: "button",
|
|
796
|
+
"data-dsh-reasoning-model": "",
|
|
797
|
+
"data-search": search,
|
|
798
|
+
onclick: function () { openEditor(model.index); },
|
|
799
|
+
}, [
|
|
800
|
+
el("div", {}, [
|
|
801
|
+
el("div", { "data-dsh-reasoning-model-name": "", text: model.name }),
|
|
802
|
+
model.name !== model.id ? el("div", { "data-dsh-reasoning-model-id": "", text: model.id }) : null,
|
|
803
|
+
el("div", { "data-dsh-reasoning-model-meta": "" }, [
|
|
804
|
+
el("span", statusAttrs),
|
|
805
|
+
active ? el("span", { "data-current": "", text: "当前对话" }) : null,
|
|
806
|
+
el("span", { text: officialStatus(model) }),
|
|
807
|
+
]),
|
|
808
|
+
]),
|
|
809
|
+
el("span", { "data-chevron": "", html: icons.chevron }),
|
|
810
|
+
]);
|
|
811
|
+
row.toggleAttribute("data-current", active);
|
|
812
|
+
if (active) row.setAttribute("aria-current", "true");
|
|
813
|
+
modelList.appendChild(row);
|
|
814
|
+
})(provider.models[i]);
|
|
815
|
+
}
|
|
816
|
+
body.appendChild(modelList);
|
|
817
|
+
body.appendChild(searchEmpty);
|
|
818
|
+
filterRows(state.query);
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
function renderLevelRows(section, model) {
|
|
822
|
+
var official = officialMap(model);
|
|
823
|
+
for (var i = 1; i < LEVELS.length; i++) {
|
|
824
|
+
(function (level) {
|
|
825
|
+
var field = state.edit.levels[level];
|
|
826
|
+
var isOfficial = Object.prototype.hasOwnProperty.call(official, level) && official[level] != null;
|
|
827
|
+
var row;
|
|
828
|
+
var inputId = "dsh-reasoning-level-" + level;
|
|
829
|
+
var wire = el("input", {
|
|
830
|
+
type: "text",
|
|
831
|
+
"data-dsh-reasoning-wire": "",
|
|
832
|
+
value: field.wire,
|
|
833
|
+
disabled: !field.checked,
|
|
834
|
+
placeholder: "线上拼写",
|
|
835
|
+
oninput: function (event) {
|
|
836
|
+
field.wire = event.target.value;
|
|
837
|
+
markEdited();
|
|
838
|
+
},
|
|
839
|
+
});
|
|
840
|
+
var checkbox = el("input", {
|
|
841
|
+
id: inputId,
|
|
842
|
+
type: "checkbox",
|
|
843
|
+
checked: field.checked,
|
|
844
|
+
"aria-label": "启用" + LEVEL_LABELS[level],
|
|
845
|
+
onchange: function (event) {
|
|
846
|
+
field.checked = event.target.checked;
|
|
847
|
+
if (field.checked && !field.wire) field.wire = isOfficial ? String(official[level]) : level;
|
|
848
|
+
wire.value = field.wire;
|
|
849
|
+
wire.disabled = !field.checked;
|
|
850
|
+
row.toggleAttribute("data-active", field.checked);
|
|
851
|
+
if (!field.checked && state.edit.defaultReasoning === level) {
|
|
852
|
+
state.edit.defaultReasoning = "";
|
|
853
|
+
var defaultSelect = document.querySelector("[data-dsh-reasoning-default]");
|
|
854
|
+
if (defaultSelect) defaultSelect.value = "";
|
|
855
|
+
}
|
|
856
|
+
markEdited();
|
|
857
|
+
},
|
|
858
|
+
});
|
|
859
|
+
row = el("div", { "data-dsh-reasoning-level": "" }, [
|
|
860
|
+
checkbox,
|
|
861
|
+
el("label", { for: inputId }, [
|
|
862
|
+
el("div", { "data-dsh-reasoning-level-name": "", text: LEVEL_LABELS[level] + " " + level }),
|
|
863
|
+
el("div", { "data-dsh-reasoning-level-detail": "", text: isOfficial ? "官方支持" : "自定义档位" }),
|
|
864
|
+
]),
|
|
865
|
+
wire,
|
|
866
|
+
]);
|
|
867
|
+
row.toggleAttribute("data-active", field.checked);
|
|
868
|
+
section.appendChild(row);
|
|
869
|
+
})(LEVELS[i]);
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
function renderEditor(body, view) {
|
|
874
|
+
var provider = selectedProvider();
|
|
875
|
+
var model = selectedModel();
|
|
876
|
+
if (!provider || !model || !state.edit) {
|
|
877
|
+
state.modelIndex = null;
|
|
878
|
+
state.edit = null;
|
|
879
|
+
state.discardConfirm = false;
|
|
880
|
+
return;
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
body.appendChild(el("div", { "data-dsh-reasoning-editor-head": "" }, [
|
|
884
|
+
iconButton(icons.back, "返回模型列表", closeEditor),
|
|
885
|
+
el("div", { "data-dsh-reasoning-editor-copy": "" }, [
|
|
886
|
+
el("div", { "data-dsh-reasoning-editor-name": "", text: model.name }),
|
|
887
|
+
el("div", { "data-dsh-reasoning-editor-id": "", text: provider.id + " / " + model.id }),
|
|
888
|
+
]),
|
|
889
|
+
]));
|
|
890
|
+
|
|
891
|
+
var offInputId = "dsh-reasoning-off-switch";
|
|
892
|
+
var offSwitch = el("input", {
|
|
893
|
+
id: offInputId,
|
|
894
|
+
type: "checkbox",
|
|
895
|
+
checked: !!state.edit.off,
|
|
896
|
+
role: "switch",
|
|
897
|
+
"aria-checked": String(!!state.edit.off),
|
|
898
|
+
"aria-label": "关闭该模型的推理",
|
|
899
|
+
onchange: function (event) {
|
|
900
|
+
var wasOff = state.edit.off;
|
|
901
|
+
state.edit.off = !!event.target.checked;
|
|
902
|
+
if (state.edit.off) state.edit.defaultReasoning = "";
|
|
903
|
+
else if (wasOff && enabledLevels().length === 0) applyOfficialLevels(model);
|
|
904
|
+
rerenderEditor();
|
|
905
|
+
},
|
|
906
|
+
});
|
|
907
|
+
var offRow = el("div", { "data-dsh-reasoning-off": "" }, [
|
|
908
|
+
offSwitch,
|
|
909
|
+
el("label", { for: offInputId }, [
|
|
910
|
+
el("div", { "data-dsh-reasoning-level-name": "", text: "关闭该模型的推理" }),
|
|
911
|
+
el("div", { "data-dsh-reasoning-level-detail": "", text: state.edit.off ? "推理等级已隐藏;保存后会同步到对话模型菜单。" : "仅影响此 Provider 下的当前模型,不改动其他模型的默认强度或协议。" }),
|
|
912
|
+
]),
|
|
913
|
+
el("span", { "data-dsh-reasoning-off-state": "", text: state.edit.off ? "已关闭" : "已启用" }),
|
|
914
|
+
]);
|
|
915
|
+
offRow.toggleAttribute("data-active", !!state.edit.off);
|
|
916
|
+
|
|
917
|
+
var levelsSection = el("section", { "data-dsh-reasoning-section": "" }, [
|
|
918
|
+
el("div", { "data-dsh-reasoning-section-head": "" }, [
|
|
919
|
+
el("div", { "data-dsh-reasoning-section-title": "", text: "可用思考等级" }),
|
|
920
|
+
el("div", { "data-dsh-reasoning-section-note": "", text: state.edit.off ? "推理已关闭" : "设置模型可选档位" }),
|
|
921
|
+
]),
|
|
922
|
+
offRow,
|
|
923
|
+
]);
|
|
924
|
+
if (state.edit.off) {
|
|
925
|
+
levelsSection.appendChild(el("div", { "data-dsh-reasoning-off-callout": "", role: "status" }, [
|
|
926
|
+
el("div", { "data-dsh-reasoning-off-callout-title": "", text: "推理已关闭" }),
|
|
927
|
+
el("div", { "data-dsh-reasoning-off-callout-copy": "", text: "保存并同步后,此模型不会在对话框中显示推理等级。重新开启开关后可恢复编辑档位。" }),
|
|
928
|
+
]));
|
|
929
|
+
} else {
|
|
930
|
+
levelsSection.appendChild(el("div", { "data-dsh-reasoning-quick": "" }, [
|
|
931
|
+
el("button", { type: "button", "data-dsh-reasoning-btn": "", text: "同步官方档位", disabled: !(model.official && model.official.reasoning), onclick: applyOfficial }),
|
|
932
|
+
el("button", { type: "button", "data-dsh-reasoning-btn": "", text: "恢复当前配置", onclick: restoreCurrent }),
|
|
933
|
+
]));
|
|
934
|
+
renderLevelRows(levelsSection, model);
|
|
935
|
+
}
|
|
936
|
+
body.appendChild(levelsSection);
|
|
937
|
+
|
|
938
|
+
if (state.edit.off) {
|
|
939
|
+
body.appendChild(el("div", { "data-dsh-reasoning-scope-note": "", text: "Provider 默认强度与协议设置保持不变;关闭推理只影响此模型。" }));
|
|
940
|
+
} else {
|
|
941
|
+
var defaultOptions = [
|
|
942
|
+
el("option", { value: "", text: "不设置 Provider 默认值" }),
|
|
943
|
+
el("option", { value: "off", text: "off · 不思考" }),
|
|
944
|
+
];
|
|
945
|
+
for (var i = 1; i < LEVELS.length; i++) {
|
|
946
|
+
var level = LEVELS[i];
|
|
947
|
+
defaultOptions.push(el("option", {
|
|
948
|
+
value: level,
|
|
949
|
+
text: level + " · " + LEVEL_LABELS[level],
|
|
950
|
+
disabled: !state.edit.levels[level].checked,
|
|
951
|
+
}));
|
|
952
|
+
}
|
|
953
|
+
var defaultSelect = el("select", {
|
|
954
|
+
"data-dsh-reasoning-select": "",
|
|
955
|
+
"data-dsh-reasoning-default": "",
|
|
956
|
+
value: state.edit.defaultReasoning,
|
|
957
|
+
onchange: function (event) { state.edit.defaultReasoning = event.target.value; markEdited(); },
|
|
958
|
+
}, defaultOptions);
|
|
959
|
+
|
|
960
|
+
var formatOptions = [el("option", { value: "", text: "自动检测" })];
|
|
961
|
+
var formats = state.list && state.list.thinkingFormats ? state.list.thinkingFormats : [];
|
|
962
|
+
for (var fi = 0; fi < formats.length; fi++) formatOptions.push(el("option", { value: formats[fi], text: formats[fi] }));
|
|
963
|
+
var formatSelect = el("select", {
|
|
964
|
+
"data-dsh-reasoning-select": "",
|
|
965
|
+
value: state.edit.thinkingFormat,
|
|
966
|
+
onchange: function (event) { state.edit.thinkingFormat = event.target.value; markEdited(); },
|
|
967
|
+
}, formatOptions);
|
|
968
|
+
|
|
969
|
+
var effortSelect = el("select", {
|
|
970
|
+
"data-dsh-reasoning-select": "",
|
|
971
|
+
value: state.edit.supportsReasoningEffort,
|
|
972
|
+
onchange: function (event) { state.edit.supportsReasoningEffort = event.target.value; markEdited(); },
|
|
973
|
+
}, [
|
|
974
|
+
el("option", { value: "", text: "自动检测" }),
|
|
975
|
+
el("option", { value: "true", text: "启用 reasoning_effort" }),
|
|
976
|
+
el("option", { value: "false", text: "不发送 reasoning_effort" }),
|
|
977
|
+
]);
|
|
978
|
+
|
|
979
|
+
body.appendChild(el("section", { "data-dsh-reasoning-section": "" }, [
|
|
980
|
+
el("div", { "data-dsh-reasoning-section-head": "" }, [
|
|
981
|
+
el("div", { "data-dsh-reasoning-section-title": "", text: "默认与协议" }),
|
|
982
|
+
el("div", { "data-dsh-reasoning-section-note": "", text: "Provider 级设置,影响同一 Provider 的模型" }),
|
|
983
|
+
]),
|
|
984
|
+
el("div", { "data-dsh-reasoning-form": "" }, [
|
|
985
|
+
el("label", { "data-dsh-reasoning-label": "", text: "新对话默认强度" }), defaultSelect,
|
|
986
|
+
el("label", { "data-dsh-reasoning-label": "", text: "思考内容格式" }), formatSelect,
|
|
987
|
+
el("label", { "data-dsh-reasoning-label": "", text: "reasoning_effort 参数" }), effortSelect,
|
|
988
|
+
]),
|
|
989
|
+
]));
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
if (state.discardConfirm) {
|
|
993
|
+
view.appendChild(el("div", { "data-dsh-reasoning-actions": "" }, [
|
|
994
|
+
el("div", { "data-dsh-reasoning-confirm": "" }, [
|
|
995
|
+
el("div", { "data-dsh-reasoning-confirm-copy": "", text: "放弃尚未保存的修改?" }),
|
|
996
|
+
el("button", { type: "button", "data-dsh-reasoning-btn": "", text: "继续编辑", onclick: function () { state.discardConfirm = false; publish(); } }),
|
|
997
|
+
el("button", { type: "button", "data-dsh-reasoning-btn": "primary", text: "放弃修改", onclick: discardEditor }),
|
|
998
|
+
]),
|
|
999
|
+
]));
|
|
1000
|
+
} else {
|
|
1001
|
+
view.appendChild(el("div", { "data-dsh-reasoning-actions": "" }, [
|
|
1002
|
+
el("div", { "data-dsh-reasoning-save-state": "", text: state.saving ? "正在校验并同步对话模型" : (isDirty() ? (state.edit.off ? "关闭推理待保存" : "有未保存的修改") : "当前没有修改") }),
|
|
1003
|
+
el("button", { type: "button", "data-dsh-reasoning-btn": "", text: "返回", disabled: state.saving, onclick: closeEditor }),
|
|
1004
|
+
el("button", { type: "button", "data-dsh-reasoning-btn": "primary", "data-dsh-reasoning-save": "", text: state.saving ? "同步中..." : (state.edit.off ? "保存并关闭" : "保存并同步"), disabled: state.saving || !isDirty(), onclick: saveEditor }),
|
|
1005
|
+
]));
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
function renderPanel() {
|
|
1010
|
+
var view = popoverView();
|
|
1011
|
+
if (!view) return;
|
|
1012
|
+
view.textContent = "";
|
|
1013
|
+
renderHeader(view);
|
|
1014
|
+
renderNotice(view);
|
|
1015
|
+
|
|
1016
|
+
var scroll = el("div", { "data-dsh-reasoning-scroll": "" });
|
|
1017
|
+
var body = el("div", { "data-dsh-reasoning-body": "" });
|
|
1018
|
+
scroll.appendChild(body);
|
|
1019
|
+
view.appendChild(scroll);
|
|
1020
|
+
|
|
1021
|
+
if (state.loading && !state.list) renderLoading(body);
|
|
1022
|
+
else if (state.error && !state.list) {
|
|
1023
|
+
body.appendChild(el("div", { "data-dsh-reasoning-empty": "" }, [
|
|
1024
|
+
el("div", { html: icons.info }),
|
|
1025
|
+
el("div", { text: "加载失败:" + state.error }),
|
|
1026
|
+
el("button", { type: "button", "data-dsh-reasoning-btn": "", text: "重试", onclick: function () { refresh(); } }),
|
|
1027
|
+
]));
|
|
1028
|
+
} else if (state.modelIndex !== null) renderEditor(body, view);
|
|
1029
|
+
else renderModelList(body);
|
|
1030
|
+
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
function mountPanel() {
|
|
1034
|
+
var view = document.createElement("div");
|
|
1035
|
+
view.setAttribute("data-dsh-reasoning-view", "");
|
|
1036
|
+
document.body.appendChild(view);
|
|
1037
|
+
var sidebar;
|
|
1038
|
+
var sidebarObserver = typeof ResizeObserver === "function" ? new ResizeObserver(syncBounds) : null;
|
|
1039
|
+
var unsubscribeRender = subscribe(renderPanel);
|
|
1040
|
+
|
|
1041
|
+
function syncBounds() {
|
|
1042
|
+
var next = document.querySelector('[data-pane="sidebar"], [class*="sidebarCol"]');
|
|
1043
|
+
if (next !== sidebar) {
|
|
1044
|
+
if (sidebarObserver) sidebarObserver.disconnect();
|
|
1045
|
+
sidebar = next || undefined;
|
|
1046
|
+
if (sidebarObserver && sidebar) sidebarObserver.observe(sidebar);
|
|
1047
|
+
}
|
|
1048
|
+
if (!sidebar) return;
|
|
1049
|
+
var rect = sidebar.getBoundingClientRect();
|
|
1050
|
+
var width = Math.min(420, Math.max(300, window.innerWidth - rect.right - 16));
|
|
1051
|
+
var left = Math.min(rect.right + 8, window.innerWidth - width - 8);
|
|
1052
|
+
view.style.left = Math.max(0, left) + "px";
|
|
1053
|
+
view.style.top = Math.max(0, rect.top) + "px";
|
|
1054
|
+
view.style.width = width + "px";
|
|
1055
|
+
view.style.height = Math.max(220, Math.min(rect.height, window.innerHeight - Math.max(0, rect.top))) + "px";
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
function syncOpen() {
|
|
1059
|
+
syncBounds();
|
|
1060
|
+
view.toggleAttribute("data-open", state.open);
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
var unsubscribeOpen = subscribe(syncOpen);
|
|
1064
|
+
var observer = new MutationObserver(syncBounds);
|
|
1065
|
+
observer.observe(document.body, { childList: true, subtree: true });
|
|
1066
|
+
window.addEventListener("resize", syncBounds);
|
|
1067
|
+
syncBounds();
|
|
1068
|
+
|
|
1069
|
+
return function () {
|
|
1070
|
+
observer.disconnect();
|
|
1071
|
+
if (sidebarObserver) sidebarObserver.disconnect();
|
|
1072
|
+
window.removeEventListener("resize", syncBounds);
|
|
1073
|
+
unsubscribeOpen();
|
|
1074
|
+
unsubscribeRender();
|
|
1075
|
+
view.removeAttribute("data-open");
|
|
1076
|
+
view.remove();
|
|
1077
|
+
};
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
function mountPanelMutualExclusion() {
|
|
1081
|
+
function onPanelOpen(event) {
|
|
1082
|
+
if (event && event.detail && event.detail.panel !== PANEL_ID && state.open) setOpen(false, false);
|
|
1083
|
+
}
|
|
1084
|
+
window.addEventListener(PANEL_EVENT, onPanelOpen);
|
|
1085
|
+
return function () { window.removeEventListener(PANEL_EVENT, onPanelOpen); };
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
function mountSidebarAutoClose() {
|
|
1089
|
+
function onClick(event) {
|
|
1090
|
+
if (!state.open) return;
|
|
1091
|
+
var target = event.target;
|
|
1092
|
+
if (!(target instanceof Element)) return;
|
|
1093
|
+
if (target.closest("[data-dsh-reasoning-entry], [data-dsh-reasoning-view]")) return;
|
|
1094
|
+
setOpen(false);
|
|
1095
|
+
}
|
|
1096
|
+
function onKeydown(event) {
|
|
1097
|
+
if (state.open && event.key === "Escape") {
|
|
1098
|
+
if (state.modelIndex !== null) closeEditor();
|
|
1099
|
+
else setOpen(false);
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1102
|
+
document.addEventListener("click", onClick, true);
|
|
1103
|
+
document.addEventListener("keydown", onKeydown, true);
|
|
1104
|
+
return function () {
|
|
1105
|
+
document.removeEventListener("click", onClick, true);
|
|
1106
|
+
document.removeEventListener("keydown", onKeydown, true);
|
|
1107
|
+
};
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
function mountEntry() {
|
|
1111
|
+
var entry = el("button", {
|
|
1112
|
+
"data-dsh-reasoning-entry": "",
|
|
1113
|
+
type: "button",
|
|
1114
|
+
title: "思考强度配置",
|
|
1115
|
+
"aria-label": "思考强度",
|
|
1116
|
+
}, [
|
|
1117
|
+
el("span", { html: icons.brain }),
|
|
1118
|
+
el("span", { text: "思考强度", class: "alabel" }),
|
|
1119
|
+
]);
|
|
1120
|
+
entry.addEventListener("click", function () {
|
|
1121
|
+
toggle();
|
|
1122
|
+
if (document.activeElement === entry) entry.blur();
|
|
1123
|
+
});
|
|
1124
|
+
|
|
1125
|
+
var root;
|
|
1126
|
+
var placed = false;
|
|
1127
|
+
function placeEntry(nextRoot) {
|
|
1128
|
+
var button = newSessionButton(nextRoot);
|
|
1129
|
+
if (!button) return false;
|
|
1130
|
+
if (entry.parentElement !== nextRoot) {
|
|
1131
|
+
var row = button.closest('[class*="logoRow"]');
|
|
1132
|
+
var base = row && row.parentElement === nextRoot ? row : button;
|
|
1133
|
+
nextRoot.insertBefore(entry, base.nextElementSibling);
|
|
1134
|
+
}
|
|
1135
|
+
return true;
|
|
1136
|
+
}
|
|
1137
|
+
function tryPlace() {
|
|
1138
|
+
if (root && !root.isConnected) { root = undefined; placed = false; }
|
|
1139
|
+
if (!placed) {
|
|
1140
|
+
root = root || sidebarRoot();
|
|
1141
|
+
if (!root) return;
|
|
1142
|
+
placed = placeEntry(root);
|
|
1143
|
+
}
|
|
1144
|
+
if (placed && !document.body.contains(entry)) { placed = false; root = undefined; tryPlace(); }
|
|
1145
|
+
}
|
|
1146
|
+
var observer = new MutationObserver(tryPlace);
|
|
1147
|
+
observer.observe(document.body, { childList: true, subtree: true });
|
|
1148
|
+
var unsubscribe = subscribe(function () {
|
|
1149
|
+
entry.toggleAttribute("data-active", state.open);
|
|
1150
|
+
});
|
|
1151
|
+
tryPlace();
|
|
1152
|
+
|
|
1153
|
+
return function () {
|
|
1154
|
+
observer.disconnect();
|
|
1155
|
+
unsubscribe();
|
|
1156
|
+
entry.remove();
|
|
1157
|
+
};
|
|
1158
|
+
}
|
|
1159
|
+
|
|
1160
|
+
function attachConversationSync(ctx) {
|
|
1161
|
+
if (!ctx || typeof ctx.inject !== "function") return;
|
|
1162
|
+
ctx.inject(["modelDirectories"], function (scope) {
|
|
1163
|
+
var resolver = scope.modelDirectories || (typeof scope.get === "function" ? scope.get("modelDirectories") : undefined);
|
|
1164
|
+
if (!resolver) return;
|
|
1165
|
+
modelDirectories = resolver;
|
|
1166
|
+
var queued = false;
|
|
1167
|
+
function update() {
|
|
1168
|
+
if (queued) return;
|
|
1169
|
+
queued = true;
|
|
1170
|
+
Promise.resolve().then(function () {
|
|
1171
|
+
return syncConversation();
|
|
1172
|
+
}).then(function () {
|
|
1173
|
+
if (state.list && !state.providerPinned && state.conversation && !state.conversation.ambiguous && providerById(state.conversation.provider)) {
|
|
1174
|
+
state.providerId = state.conversation.provider;
|
|
1175
|
+
}
|
|
1176
|
+
if (state.open) publish();
|
|
1177
|
+
}).catch(function () {}).finally(function () {
|
|
1178
|
+
queued = false;
|
|
1179
|
+
});
|
|
1180
|
+
}
|
|
1181
|
+
var stops = knownDirectories().map(function (directory) {
|
|
1182
|
+
return directory.store.subscribe(update);
|
|
1183
|
+
});
|
|
1184
|
+
update();
|
|
1185
|
+
if (scope.effect) {
|
|
1186
|
+
scope.effect(function () {
|
|
1187
|
+
return function () {
|
|
1188
|
+
for (var i = 0; i < stops.length; i++) stops[i]();
|
|
1189
|
+
if (modelDirectories === resolver) {
|
|
1190
|
+
modelDirectories = undefined;
|
|
1191
|
+
state.conversation = null;
|
|
1192
|
+
if (state.open) publish();
|
|
1193
|
+
}
|
|
1194
|
+
};
|
|
1195
|
+
}, NS + ": conversation sync");
|
|
1196
|
+
}
|
|
1197
|
+
});
|
|
1198
|
+
}
|
|
1199
|
+
|
|
1200
|
+
function apply(ctx) {
|
|
1201
|
+
try {
|
|
1202
|
+
document.documentElement.removeAttribute("data-dsh-reasoning-active");
|
|
1203
|
+
// Defensive cleanup: a previously stuck drawer instance must never
|
|
1204
|
+
// survive a hot-swap of this module.
|
|
1205
|
+
var strays = document.querySelectorAll("[data-dsh-reasoning-view], [data-dsh-reasoning-entry], [data-dsh-reasoning-toast]");
|
|
1206
|
+
for (var si = 0; si < strays.length; si++) strays[si].remove();
|
|
1207
|
+
injectCss();
|
|
1208
|
+
attachConversationSync(ctx);
|
|
1209
|
+
var disposers = [mountEntry(), mountPanel(), mountPanelMutualExclusion(), mountSidebarAutoClose()];
|
|
1210
|
+
if (ctx && ctx.effect) {
|
|
1211
|
+
ctx.effect(function () {
|
|
1212
|
+
return function () {
|
|
1213
|
+
clearTimeout(noticeTimer);
|
|
1214
|
+
setOpen(false);
|
|
1215
|
+
for (var i = 0; i < disposers.length; i++) disposers[i]();
|
|
1216
|
+
};
|
|
1217
|
+
}, NS + ": mounts");
|
|
1218
|
+
}
|
|
1219
|
+
} catch (error) {
|
|
1220
|
+
console.warn("[dsh-reasoning-effort] mount failed:", error);
|
|
1221
|
+
}
|
|
1222
|
+
}
|
|
1223
|
+
|
|
1224
|
+
exports.apply = apply;
|
|
1225
|
+
exports.inject = ["slots", "locale", "modelDirectories"];
|
|
1226
|
+
return module.exports;
|
|
1227
|
+
},
|
|
1228
|
+
});
|