@kevin5251984/guild 0.2.19 → 0.2.21
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/package.json +2 -2
- package/src/cli.ts +2 -5
- package/src/db.ts +39 -6
- package/src/generate.ts +3 -3
- package/src/handlers.ts +126 -50
- package/src/harness.ts +20 -4
- package/src/host-browse.ts +149 -4
- package/src/llm.ts +37 -15
- package/src/mcp.ts +32 -5
- package/src/mention.ts +80 -12
- package/src/oauth.ts +2 -2
- package/src/opencode-free.ts +3 -2
- package/src/public/chat.css +6 -0
- package/src/public/chat.html +260 -47
- package/src/public/i18n.js +6 -0
- package/src/public/md.js +18 -1
- package/src/public/mobile.css +224 -14
- package/src/public/mobile.html +344 -22
- package/src/public/settings.html +51 -8
- package/src/reasoning-catalog.ts +346 -0
- package/src/router.ts +172 -9
- package/src/store.ts +109 -38
- package/src/subagent.ts +10 -5
- package/src/tools.ts +8 -3
- package/src/version.ts +25 -0
- package/vendor/protocol/src/index.ts +19 -2
package/src/public/chat.html
CHANGED
|
@@ -167,12 +167,7 @@
|
|
|
167
167
|
<a class="model-choice" href="/settings" data-i18n="model.settings">狀態欄</a>
|
|
168
168
|
</div>
|
|
169
169
|
</div>
|
|
170
|
-
<select id="model-reasoning" hidden>
|
|
171
|
-
<option value="minimal" data-i18n="reason.min">最低</option>
|
|
172
|
-
<option value="low" data-i18n="reason.low">低</option>
|
|
173
|
-
<option value="medium" data-i18n="reason.mid">中</option>
|
|
174
|
-
<option value="high" data-i18n="reason.high">高</option>
|
|
175
|
-
</select>
|
|
170
|
+
<select id="model-reasoning" hidden></select>
|
|
176
171
|
<input type="checkbox" id="model-fast" hidden />
|
|
177
172
|
</div>
|
|
178
173
|
</div>
|
|
@@ -266,6 +261,13 @@
|
|
|
266
261
|
</div>
|
|
267
262
|
<script>
|
|
268
263
|
const COLORS = ["#7c6af7", "#5b8def", "#2ea887", "#e07a3d", "#d4537e"];
|
|
264
|
+
const SEAT_HUE = {
|
|
265
|
+
infra: "#5b8def",
|
|
266
|
+
pm: "#2ea887",
|
|
267
|
+
rd: "#e07a3d",
|
|
268
|
+
design: "#7c6af7",
|
|
269
|
+
marketing: "#d4537e",
|
|
270
|
+
};
|
|
269
271
|
const CHANNEL_ROSTER_CAP = 6;
|
|
270
272
|
function isGeneralChannel(ch) {
|
|
271
273
|
return Boolean(ch && (ch.id === "channel-general" || ch.name === "general"));
|
|
@@ -321,6 +323,8 @@
|
|
|
321
323
|
};
|
|
322
324
|
|
|
323
325
|
function hue(key) {
|
|
326
|
+
const seat = SEAT_HUE[String(key).toLowerCase()];
|
|
327
|
+
if (seat) return seat;
|
|
324
328
|
let n = 0;
|
|
325
329
|
for (const ch of String(key)) n = (n + ch.charCodeAt(0) * 17) % COLORS.length;
|
|
326
330
|
return COLORS[n];
|
|
@@ -1036,14 +1040,48 @@
|
|
|
1036
1040
|
}
|
|
1037
1041
|
return out;
|
|
1038
1042
|
}
|
|
1043
|
+
function deferredHandles(text) {
|
|
1044
|
+
const raw = String(text || "");
|
|
1045
|
+
const out = [];
|
|
1046
|
+
const add = (name) => {
|
|
1047
|
+
const key = String(name || "").toLowerCase();
|
|
1048
|
+
if (key && out.indexOf(key) < 0) out.push(key);
|
|
1049
|
+
};
|
|
1050
|
+
const scan = raw.replace(/```[\s\S]*?```/g, " ");
|
|
1051
|
+
const cue =
|
|
1052
|
+
/(?:完成後|通過後|最後(?:才|由)?|才需要|才叫|才交)[^@\n]{0,24}@([A-Za-z0-9_-]+)/gi;
|
|
1053
|
+
const bare =
|
|
1054
|
+
/(?:完成後|才需要|才叫)\s*(?:call|ask|由)\s*`?@?([A-Za-z0-9_-]+)`?/gi;
|
|
1055
|
+
let row;
|
|
1056
|
+
while ((row = cue.exec(scan))) add(row[1]);
|
|
1057
|
+
while ((row = bare.exec(scan))) add(row[1]);
|
|
1058
|
+
const later =
|
|
1059
|
+
/^[ \t]*(?:\d+[.)、]\s*|[-*•]\s+)(?:通過後|最後|然後|之後|完成後)\s*`?@([A-Za-z0-9_-]+)`?/i;
|
|
1060
|
+
const lines = raw.split(/\r?\n/);
|
|
1061
|
+
for (let i = 0; i < lines.length; i++) {
|
|
1062
|
+
const hit = lines[i].match(later);
|
|
1063
|
+
if (hit) add(hit[1]);
|
|
1064
|
+
}
|
|
1065
|
+
return out;
|
|
1066
|
+
}
|
|
1039
1067
|
function summonedBotIds(text) {
|
|
1040
1068
|
const raw = String(text || "");
|
|
1069
|
+
const deferred = new Set(deferredHandles(raw));
|
|
1070
|
+
const members = new Set(
|
|
1071
|
+
state.kind === "channel"
|
|
1072
|
+
? ((currentChannel() && currentChannel().memberIds) || [])
|
|
1073
|
+
: state.kind === "dm"
|
|
1074
|
+
? [state.id]
|
|
1075
|
+
: [],
|
|
1076
|
+
);
|
|
1041
1077
|
const known = new Map(
|
|
1042
|
-
(state.bots || [])
|
|
1078
|
+
(state.bots || [])
|
|
1079
|
+
.filter((bot) => !members.size || members.has(bot.id))
|
|
1080
|
+
.map((bot) => [String(bot.handle).toLowerCase(), bot.id]),
|
|
1043
1081
|
);
|
|
1044
1082
|
const out = [];
|
|
1045
|
-
const push = (id) => {
|
|
1046
|
-
if (id && !out.includes(id)) out.push(id);
|
|
1083
|
+
const push = (id, handle) => {
|
|
1084
|
+
if (id && !deferred.has(handle) && !out.includes(id)) out.push(id);
|
|
1047
1085
|
};
|
|
1048
1086
|
let fence = false;
|
|
1049
1087
|
const lines = raw.split(/\r?\n/);
|
|
@@ -1060,11 +1098,21 @@
|
|
|
1060
1098
|
if (!m) continue;
|
|
1061
1099
|
const names = m[1].match(/@([A-Za-z0-9_-]+)/g) || [];
|
|
1062
1100
|
for (let n = 0; n < names.length; n++) {
|
|
1063
|
-
|
|
1101
|
+
const handle = names[n].slice(1).toLowerCase();
|
|
1102
|
+
push(known.get(handle), handle);
|
|
1064
1103
|
}
|
|
1065
1104
|
}
|
|
1066
1105
|
if (out.length) return out;
|
|
1067
|
-
return mentionedBotIds(raw)
|
|
1106
|
+
return mentionedBotIds(raw)
|
|
1107
|
+
.filter((id) => {
|
|
1108
|
+
const bot = (state.bots || []).find((row) => row.id === id);
|
|
1109
|
+
return (
|
|
1110
|
+
bot &&
|
|
1111
|
+
(!members.size || members.has(id)) &&
|
|
1112
|
+
!deferred.has(String(bot.handle).toLowerCase())
|
|
1113
|
+
);
|
|
1114
|
+
})
|
|
1115
|
+
.slice(0, 1);
|
|
1068
1116
|
}
|
|
1069
1117
|
function lastBotAuthor() {
|
|
1070
1118
|
const msgs = state.messages || [];
|
|
@@ -1244,7 +1292,20 @@
|
|
|
1244
1292
|
}
|
|
1245
1293
|
function botModelMeta(bot) {
|
|
1246
1294
|
const model = botModelLabel(bot) || "—";
|
|
1247
|
-
const
|
|
1295
|
+
const ref = botModelRef(bot);
|
|
1296
|
+
const spec = (() => {
|
|
1297
|
+
if (!ref) return null;
|
|
1298
|
+
const hit = allModels().find(
|
|
1299
|
+
(row) => row.provider === ref.provider && row.model === ref.model,
|
|
1300
|
+
);
|
|
1301
|
+
return (hit && hit.reasoning) || null;
|
|
1302
|
+
})();
|
|
1303
|
+
const reasonVal = clampEffort(
|
|
1304
|
+
ref && ref.reasoning,
|
|
1305
|
+
spec,
|
|
1306
|
+
Boolean(modelCfg && modelCfg.fast),
|
|
1307
|
+
);
|
|
1308
|
+
const reason = reasonVal ? reasonLabel(reasonVal) : "—";
|
|
1248
1309
|
const provider = botProviderLabel(bot) || "—";
|
|
1249
1310
|
return model + " · " + reason + " · " + provider;
|
|
1250
1311
|
}
|
|
@@ -1652,6 +1713,7 @@
|
|
|
1652
1713
|
thinking: row.thinking || "",
|
|
1653
1714
|
steps: Array.isArray(row.steps) ? row.steps.slice(-5) : [],
|
|
1654
1715
|
startedAt: row.startedAt || "",
|
|
1716
|
+
paused: Boolean(row.paused),
|
|
1655
1717
|
}));
|
|
1656
1718
|
}
|
|
1657
1719
|
function rebuildBusyBots() {
|
|
@@ -1680,6 +1742,7 @@
|
|
|
1680
1742
|
thinking: row.thinking || "",
|
|
1681
1743
|
steps: Array.isArray(row.steps) ? row.steps.slice(-5) : [],
|
|
1682
1744
|
startedAt: row.startedAt || "",
|
|
1745
|
+
paused: Boolean(row.paused),
|
|
1683
1746
|
room: { kind: r.kind, id: r.id },
|
|
1684
1747
|
}));
|
|
1685
1748
|
state.lives = others.concat(tagged);
|
|
@@ -1730,24 +1793,38 @@
|
|
|
1730
1793
|
? '<span class="clock">' + Math.floor(elapsed / 1000) + "s</span>"
|
|
1731
1794
|
: "";
|
|
1732
1795
|
const botId = live && live.botId ? live.botId : "";
|
|
1796
|
+
const paused = Boolean(live && live.paused);
|
|
1733
1797
|
const actions = botId
|
|
1734
1798
|
? '<div class="turn-actions">' +
|
|
1799
|
+
(paused
|
|
1800
|
+
? '<button type="button" class="turn-continue" data-live-continue="' +
|
|
1801
|
+
escapeHtml(botId) +
|
|
1802
|
+
'">' +
|
|
1803
|
+
t("live.continue") +
|
|
1804
|
+
"</button>"
|
|
1805
|
+
: '<button type="button" class="turn-pause" data-live-pause="' +
|
|
1806
|
+
escapeHtml(botId) +
|
|
1807
|
+
'">' +
|
|
1808
|
+
t("live.pause") +
|
|
1809
|
+
"</button>") +
|
|
1735
1810
|
'<button type="button" class="turn-stop" data-live-stop="' +
|
|
1736
1811
|
escapeHtml(botId) +
|
|
1737
1812
|
'">' +
|
|
1738
1813
|
t("live.stop") +
|
|
1739
1814
|
"</button>" +
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1815
|
+
(paused
|
|
1816
|
+
? ""
|
|
1817
|
+
: '<button type="button" class="turn-steer" data-live-steer="' +
|
|
1818
|
+
escapeHtml(botId) +
|
|
1819
|
+
'">' +
|
|
1820
|
+
t("live.steer") +
|
|
1821
|
+
"</button>") +
|
|
1745
1822
|
"</div>"
|
|
1746
1823
|
: "";
|
|
1747
1824
|
return (
|
|
1748
1825
|
'<div class="turn-live">' +
|
|
1749
1826
|
'<div class="turn-status">' +
|
|
1750
|
-
t("deepDiving") +
|
|
1827
|
+
(paused ? t("live.paused") : t("deepDiving")) +
|
|
1751
1828
|
clock +
|
|
1752
1829
|
"</div>" +
|
|
1753
1830
|
liveStepsHtml(live && live.steps) +
|
|
@@ -1768,7 +1845,9 @@
|
|
|
1768
1845
|
return (
|
|
1769
1846
|
'<article class="msg bot live" data-bot-id="' +
|
|
1770
1847
|
escapeHtml(bot.id) +
|
|
1771
|
-
'"
|
|
1848
|
+
'"' +
|
|
1849
|
+
(live.paused ? ' data-paused="1"' : "") +
|
|
1850
|
+
' role="status">' +
|
|
1772
1851
|
actor.av +
|
|
1773
1852
|
'<div class="msg-main">' +
|
|
1774
1853
|
actor.head +
|
|
@@ -1805,6 +1884,11 @@
|
|
|
1805
1884
|
const block = article.querySelector(".turn-live");
|
|
1806
1885
|
if (!block) return;
|
|
1807
1886
|
const status = block.querySelector(".turn-status");
|
|
1887
|
+
const paused = Boolean(live.paused);
|
|
1888
|
+
if ((article.getAttribute("data-paused") === "1") !== paused) {
|
|
1889
|
+
renderThread();
|
|
1890
|
+
return;
|
|
1891
|
+
}
|
|
1808
1892
|
if (status) {
|
|
1809
1893
|
const started = live.startedAt ? Date.parse(live.startedAt) : NaN;
|
|
1810
1894
|
const elapsed = Number.isFinite(started)
|
|
@@ -1814,7 +1898,7 @@
|
|
|
1814
1898
|
elapsed >= 15000
|
|
1815
1899
|
? '<span class="clock">' + Math.floor(elapsed / 1000) + "s</span>"
|
|
1816
1900
|
: "";
|
|
1817
|
-
status.innerHTML = t("deepDiving") + clock;
|
|
1901
|
+
status.innerHTML = (paused ? t("live.paused") : t("deepDiving")) + clock;
|
|
1818
1902
|
}
|
|
1819
1903
|
const html = liveStepsHtml(live.steps);
|
|
1820
1904
|
const existing = block.querySelector(".live-steps");
|
|
@@ -2267,6 +2351,18 @@
|
|
|
2267
2351
|
? "/dms/" + encodeURIComponent(r.id) + "/abort"
|
|
2268
2352
|
: "/channels/" + encodeURIComponent(r.id) + "/abort";
|
|
2269
2353
|
}
|
|
2354
|
+
function pauseUrl(room) {
|
|
2355
|
+
const r = room || state.busyRoom || { kind: state.kind, id: state.id };
|
|
2356
|
+
return r.kind === "dm"
|
|
2357
|
+
? "/dms/" + encodeURIComponent(r.id) + "/pause"
|
|
2358
|
+
: "/channels/" + encodeURIComponent(r.id) + "/pause";
|
|
2359
|
+
}
|
|
2360
|
+
function continueUrl(room) {
|
|
2361
|
+
const r = room || state.busyRoom || { kind: state.kind, id: state.id };
|
|
2362
|
+
return r.kind === "dm"
|
|
2363
|
+
? "/dms/" + encodeURIComponent(r.id) + "/continue"
|
|
2364
|
+
: "/channels/" + encodeURIComponent(r.id) + "/continue";
|
|
2365
|
+
}
|
|
2270
2366
|
function stopTurn(botId) {
|
|
2271
2367
|
const room = currentRoomRef();
|
|
2272
2368
|
(state.aborts || []).forEach((item) => {
|
|
@@ -2292,6 +2388,30 @@
|
|
|
2292
2388
|
}).catch(() => {});
|
|
2293
2389
|
setBusy(false, botId ? [botId] : [], { room: room });
|
|
2294
2390
|
}
|
|
2391
|
+
function pauseTurn(botId) {
|
|
2392
|
+
const room = currentRoomRef();
|
|
2393
|
+
fetch(pauseUrl(room), {
|
|
2394
|
+
method: "POST",
|
|
2395
|
+
headers: { "content-type": "application/json" },
|
|
2396
|
+
body: JSON.stringify(botId ? { botId: botId } : {}),
|
|
2397
|
+
}).catch(() => {});
|
|
2398
|
+
(state.lives || []).forEach((row) => {
|
|
2399
|
+
if (!botId || row.botId === botId) row.paused = true;
|
|
2400
|
+
});
|
|
2401
|
+
if (state.live && (!botId || state.live.botId === botId)) {
|
|
2402
|
+
state.live.paused = true;
|
|
2403
|
+
}
|
|
2404
|
+
renderThread();
|
|
2405
|
+
}
|
|
2406
|
+
async function continueTurn(botId) {
|
|
2407
|
+
const room = currentRoomRef();
|
|
2408
|
+
(state.lives || []).forEach((row) => {
|
|
2409
|
+
if (row.botId === botId) row.paused = false;
|
|
2410
|
+
});
|
|
2411
|
+
if (state.live && state.live.botId === botId) state.live.paused = false;
|
|
2412
|
+
renderThread();
|
|
2413
|
+
await postChat(continueUrl(room), { botId: botId }, room, [botId]);
|
|
2414
|
+
}
|
|
2295
2415
|
async function insertIntoBotTurn(botId) {
|
|
2296
2416
|
if (!composerHasPayload()) {
|
|
2297
2417
|
const draft = document.getElementById("draft");
|
|
@@ -2756,6 +2876,22 @@
|
|
|
2756
2876
|
stopTurn(liveStop.getAttribute("data-live-stop"));
|
|
2757
2877
|
return;
|
|
2758
2878
|
}
|
|
2879
|
+
const livePause = event.target.closest("[data-live-pause]");
|
|
2880
|
+
if (livePause) {
|
|
2881
|
+
event.preventDefault();
|
|
2882
|
+
event.stopImmediatePropagation();
|
|
2883
|
+
pauseTurn(livePause.getAttribute("data-live-pause"));
|
|
2884
|
+
return;
|
|
2885
|
+
}
|
|
2886
|
+
const liveContinue = event.target.closest("[data-live-continue]");
|
|
2887
|
+
if (liveContinue) {
|
|
2888
|
+
event.preventDefault();
|
|
2889
|
+
event.stopImmediatePropagation();
|
|
2890
|
+
continueTurn(liveContinue.getAttribute("data-live-continue")).catch(
|
|
2891
|
+
(err) => alert(err.message),
|
|
2892
|
+
);
|
|
2893
|
+
return;
|
|
2894
|
+
}
|
|
2759
2895
|
const liveSteer = event.target.closest("[data-live-steer]");
|
|
2760
2896
|
if (liveSteer) {
|
|
2761
2897
|
event.preventDefault();
|
|
@@ -3023,7 +3159,12 @@
|
|
|
3023
3159
|
if (bot) showBotCard(bot, event.currentTarget);
|
|
3024
3160
|
});
|
|
3025
3161
|
document.getElementById("thread").addEventListener("click", (event) => {
|
|
3026
|
-
if (
|
|
3162
|
+
if (
|
|
3163
|
+
event.target.closest(
|
|
3164
|
+
"[data-live-stop], [data-live-pause], [data-live-continue], [data-live-steer]",
|
|
3165
|
+
)
|
|
3166
|
+
)
|
|
3167
|
+
return;
|
|
3027
3168
|
const av = event.target.closest(
|
|
3028
3169
|
".avatar[data-bot-id], button.name[data-bot-id]",
|
|
3029
3170
|
);
|
|
@@ -4391,6 +4532,9 @@
|
|
|
4391
4532
|
}
|
|
4392
4533
|
setBusy(false, botIds, { room: sent });
|
|
4393
4534
|
}
|
|
4535
|
+
if (state.kind === sent.kind && state.id === sent.id) {
|
|
4536
|
+
await resumeCurrentLive().catch(() => {});
|
|
4537
|
+
}
|
|
4394
4538
|
if (ok) await flushQueued(sent);
|
|
4395
4539
|
}
|
|
4396
4540
|
async function flushQueued(sent) {
|
|
@@ -5332,6 +5476,7 @@
|
|
|
5332
5476
|
group: p.name || p.id,
|
|
5333
5477
|
ready: Boolean(p.ready),
|
|
5334
5478
|
kind: p.kind || "key",
|
|
5479
|
+
reasoning: m.reasoning || null,
|
|
5335
5480
|
});
|
|
5336
5481
|
}
|
|
5337
5482
|
}
|
|
@@ -5345,10 +5490,45 @@
|
|
|
5345
5490
|
return hit ? hit.name : ref.model;
|
|
5346
5491
|
}
|
|
5347
5492
|
function reasonLabel(value) {
|
|
5493
|
+
if (value === "none") return t("reason.none");
|
|
5348
5494
|
if (value === "minimal") return t("reason.min");
|
|
5349
5495
|
if (value === "low") return t("reason.low");
|
|
5496
|
+
if (value === "medium") return t("reason.mid");
|
|
5350
5497
|
if (value === "high") return t("reason.high");
|
|
5351
|
-
return t("reason.
|
|
5498
|
+
if (value === "xhigh") return t("reason.xhigh");
|
|
5499
|
+
if (value === "max") return t("reason.max");
|
|
5500
|
+
return value || t("reason.mid");
|
|
5501
|
+
}
|
|
5502
|
+
function activeReasoningSpec() {
|
|
5503
|
+
const ref = activeModelRef();
|
|
5504
|
+
if (!ref) return null;
|
|
5505
|
+
const hit = allModels().find(
|
|
5506
|
+
(row) => row.provider === ref.provider && row.model === ref.model,
|
|
5507
|
+
);
|
|
5508
|
+
return (hit && hit.reasoning) || null;
|
|
5509
|
+
}
|
|
5510
|
+
function effortChoices(spec) {
|
|
5511
|
+
const raw = spec && spec.supportedEfforts;
|
|
5512
|
+
if (!raw || !raw.length) return [];
|
|
5513
|
+
return spec.mandatory
|
|
5514
|
+
? raw.filter((key) => key !== "none")
|
|
5515
|
+
: raw.slice();
|
|
5516
|
+
}
|
|
5517
|
+
function clampEffort(want, spec, fast) {
|
|
5518
|
+
const choices = effortChoices(spec);
|
|
5519
|
+
if (!choices.length) return "";
|
|
5520
|
+
if (fast) {
|
|
5521
|
+
if (choices.indexOf("low") >= 0) return "low";
|
|
5522
|
+
if (choices.indexOf("minimal") >= 0) return "minimal";
|
|
5523
|
+
return choices[choices.length - 1];
|
|
5524
|
+
}
|
|
5525
|
+
if (want && choices.indexOf(want) >= 0) return want;
|
|
5526
|
+
if (spec.defaultEffort && choices.indexOf(spec.defaultEffort) >= 0) {
|
|
5527
|
+
return spec.defaultEffort;
|
|
5528
|
+
}
|
|
5529
|
+
if (choices.indexOf("high") >= 0) return "high";
|
|
5530
|
+
if (choices.indexOf("medium") >= 0) return "medium";
|
|
5531
|
+
return choices[0];
|
|
5352
5532
|
}
|
|
5353
5533
|
function speedLabel() {
|
|
5354
5534
|
return modelCfg.fast ? t("speed.fast") : t("speed.normal");
|
|
@@ -5450,25 +5630,45 @@
|
|
|
5450
5630
|
}
|
|
5451
5631
|
document.getElementById("model-results").innerHTML =
|
|
5452
5632
|
html || '<p class="model-empty">' + t("noModels") + "</p>";
|
|
5453
|
-
document.getElementById("model-reasoning").value = modelCfg.reasoning || "medium";
|
|
5454
5633
|
document.getElementById("model-fast").checked = Boolean(modelCfg.fast);
|
|
5455
|
-
const
|
|
5634
|
+
const spec = activeReasoningSpec();
|
|
5635
|
+
const choices = effortChoices(spec);
|
|
5636
|
+
const currentRef = activeModelRef();
|
|
5637
|
+
const reasonVal = clampEffort(
|
|
5638
|
+
currentRef && currentRef.reasoning,
|
|
5639
|
+
spec,
|
|
5640
|
+
Boolean(modelCfg.fast),
|
|
5641
|
+
);
|
|
5642
|
+
const reasonSel = document.getElementById("model-reasoning");
|
|
5643
|
+
reasonSel.innerHTML = choices
|
|
5644
|
+
.map(
|
|
5645
|
+
(value) =>
|
|
5646
|
+
'<option value="' +
|
|
5647
|
+
value +
|
|
5648
|
+
'">' +
|
|
5649
|
+
reasonLabel(value) +
|
|
5650
|
+
"</option>",
|
|
5651
|
+
)
|
|
5652
|
+
.join("");
|
|
5653
|
+
if (reasonVal) reasonSel.value = reasonVal;
|
|
5654
|
+
const reasonRow = document.querySelector('.model-nav [data-sheet="reasoning"]');
|
|
5655
|
+
if (reasonRow) reasonRow.hidden = !choices.length;
|
|
5656
|
+
if (!choices.length) {
|
|
5657
|
+
const pane = document.getElementById("model-sheet-reasoning");
|
|
5658
|
+
if (pane && !pane.hidden) showModelSheet("models");
|
|
5659
|
+
}
|
|
5660
|
+
const reason = choices.length ? reasonLabel(reasonVal) : "";
|
|
5456
5661
|
const speed = speedLabel();
|
|
5457
5662
|
const name = displayName(current);
|
|
5458
5663
|
document.getElementById("model-btn-label").textContent = current
|
|
5459
|
-
? name + " " + reason
|
|
5664
|
+
? name + (reason ? " " + reason : "")
|
|
5460
5665
|
: name;
|
|
5461
5666
|
document.getElementById("model-row-model").textContent = name;
|
|
5462
|
-
document.getElementById("model-row-reason").textContent = reason;
|
|
5667
|
+
document.getElementById("model-row-reason").textContent = reason || "—";
|
|
5463
5668
|
document.getElementById("model-row-speed").textContent = speed;
|
|
5464
|
-
document.getElementById("model-reason-list").innerHTML =
|
|
5465
|
-
|
|
5466
|
-
|
|
5467
|
-
["medium", t("reason.mid")],
|
|
5468
|
-
["high", t("reason.high")],
|
|
5469
|
-
]
|
|
5470
|
-
.map(([value, label]) => {
|
|
5471
|
-
const on = (modelCfg.reasoning || "medium") === value ? " on" : "";
|
|
5669
|
+
document.getElementById("model-reason-list").innerHTML = choices
|
|
5670
|
+
.map((value) => {
|
|
5671
|
+
const on = reasonVal === value ? " on" : "";
|
|
5472
5672
|
const tick = on ? '<span class="tick">✓</span>' : "";
|
|
5473
5673
|
return (
|
|
5474
5674
|
'<button type="button" class="model-choice' +
|
|
@@ -5476,7 +5676,7 @@
|
|
|
5476
5676
|
'" data-reason="' +
|
|
5477
5677
|
value +
|
|
5478
5678
|
'">' +
|
|
5479
|
-
|
|
5679
|
+
reasonLabel(value) +
|
|
5480
5680
|
tick +
|
|
5481
5681
|
"</button>"
|
|
5482
5682
|
);
|
|
@@ -5505,11 +5705,24 @@
|
|
|
5505
5705
|
async function applyChatModel(ref) {
|
|
5506
5706
|
if (state.kind !== "dm") return;
|
|
5507
5707
|
const bot = botById(state.id);
|
|
5508
|
-
if (!bot) return;
|
|
5708
|
+
if (!bot || !ref || !ref.provider || !ref.model) return;
|
|
5709
|
+
const spec = (() => {
|
|
5710
|
+
const hit = allModels().find(
|
|
5711
|
+
(row) => row.provider === ref.provider && row.model === ref.model,
|
|
5712
|
+
);
|
|
5713
|
+
return (hit && hit.reasoning) || null;
|
|
5714
|
+
})();
|
|
5715
|
+
const reason = clampEffort(
|
|
5716
|
+
document.getElementById("model-reasoning").value || ref.reasoning,
|
|
5717
|
+
spec,
|
|
5718
|
+
Boolean(document.getElementById("model-fast").checked),
|
|
5719
|
+
);
|
|
5720
|
+
const next = { provider: ref.provider, model: ref.model };
|
|
5721
|
+
if (reason) next.reasoning = reason;
|
|
5509
5722
|
const res = await fetch("/bots/" + encodeURIComponent(bot.id), {
|
|
5510
5723
|
method: "PATCH",
|
|
5511
5724
|
headers: { "content-type": "application/json" },
|
|
5512
|
-
body: JSON.stringify({ model:
|
|
5725
|
+
body: JSON.stringify({ model: next }),
|
|
5513
5726
|
});
|
|
5514
5727
|
if (!res.ok) {
|
|
5515
5728
|
const body = await res.json().catch(() => ({}));
|
|
@@ -5519,16 +5732,16 @@
|
|
|
5519
5732
|
const updated = await res.json();
|
|
5520
5733
|
const i = state.bots.findIndex((item) => item.id === bot.id);
|
|
5521
5734
|
if (i >= 0) state.bots[i] = { ...state.bots[i], model: updated.model };
|
|
5522
|
-
|
|
5523
|
-
|
|
5524
|
-
|
|
5525
|
-
|
|
5526
|
-
|
|
5527
|
-
|
|
5528
|
-
})
|
|
5529
|
-
|
|
5530
|
-
|
|
5531
|
-
}
|
|
5735
|
+
const fast = document.getElementById("model-fast").checked;
|
|
5736
|
+
if (Boolean(modelCfg.fast) !== Boolean(fast)) {
|
|
5737
|
+
await fetch("/settings/models", {
|
|
5738
|
+
method: "PUT",
|
|
5739
|
+
headers: { "content-type": "application/json" },
|
|
5740
|
+
body: JSON.stringify({ fast: fast }),
|
|
5741
|
+
}).then(async (r) => {
|
|
5742
|
+
if (r.ok) modelCfg = await r.json();
|
|
5743
|
+
});
|
|
5744
|
+
}
|
|
5532
5745
|
renderModelList();
|
|
5533
5746
|
renderNav();
|
|
5534
5747
|
}
|
package/src/public/i18n.js
CHANGED
|
@@ -90,6 +90,9 @@ var I18N_ROWS = [
|
|
|
90
90
|
["stop", "停止", "Stop"],
|
|
91
91
|
["steer.hint", "Enter 排隊 · {mod}↩ 插入這輪", "Enter to queue · {mod}↩ to steer this turn"],
|
|
92
92
|
["live.stop", "停止", "Stop"],
|
|
93
|
+
["live.pause", "暫停", "Pause"],
|
|
94
|
+
["live.continue", "繼續", "Continue"],
|
|
95
|
+
["live.paused", "已暫停", "Paused"],
|
|
93
96
|
["live.steer", "插入這輪", "Insert into turn"],
|
|
94
97
|
["steer.queue", "排隊", "Queue"],
|
|
95
98
|
["steer.insert", "插入引導", "Steer"],
|
|
@@ -119,10 +122,13 @@ var I18N_ROWS = [
|
|
|
119
122
|
["local", "本地", "Local"],
|
|
120
123
|
["you", "你", "You"],
|
|
121
124
|
["emptyParen", "(空)", "(empty)"],
|
|
125
|
+
["reason.none", "關閉", "Off"],
|
|
122
126
|
["reason.min", "最低", "Min"],
|
|
123
127
|
["reason.low", "低", "Low"],
|
|
124
128
|
["reason.mid", "中", "Mid"],
|
|
125
129
|
["reason.high", "高", "High"],
|
|
130
|
+
["reason.xhigh", "極高", "Extra high"],
|
|
131
|
+
["reason.max", "最大", "Max"],
|
|
126
132
|
["speed.normal", "標準", "Standard"],
|
|
127
133
|
["speed.fast", "快速", "Fast"],
|
|
128
134
|
["model", "模型", "Model"],
|
package/src/public/md.js
CHANGED
|
@@ -327,6 +327,23 @@ function renderMarkdown(raw) {
|
|
|
327
327
|
return html.join("");
|
|
328
328
|
}
|
|
329
329
|
|
|
330
|
+
function hydrateHtmlPreviews(root) {
|
|
331
|
+
if (!root || typeof root.querySelectorAll !== "function") return;
|
|
332
|
+
root.querySelectorAll(".md-html-preview").forEach((box) => {
|
|
333
|
+
const src = box.querySelector(".md-html-src");
|
|
334
|
+
const frame = box.querySelector(".md-html-frame");
|
|
335
|
+
if (!src || !frame || frame.dataset.ready) return;
|
|
336
|
+
frame.dataset.ready = "1";
|
|
337
|
+
const raw = src.value;
|
|
338
|
+
const lang = (box.querySelector(".md-fence-lang") || {}).textContent || "";
|
|
339
|
+
frame.srcdoc = /svg/i.test(lang)
|
|
340
|
+
? '<!doctype html><html><body style="margin:0;background:#fff">' +
|
|
341
|
+
raw +
|
|
342
|
+
"</body></html>"
|
|
343
|
+
: raw;
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
|
|
330
347
|
if (typeof module !== "undefined" && module.exports) {
|
|
331
|
-
module.exports = { renderMarkdown, inlineMd };
|
|
348
|
+
module.exports = { renderMarkdown, inlineMd, hydrateHtmlPreviews };
|
|
332
349
|
}
|