@kevin5251984/guild 0.2.12 → 0.2.14
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 +10 -8
- package/src/catalog/subagents.ts +1 -2
- package/src/chat-parts.ts +1 -6
- package/src/generate.ts +27 -55
- package/src/handlers.ts +6 -183
- package/src/harness.ts +8 -21
- package/src/image-gen.ts +1 -2
- package/src/llm.ts +7 -14
- package/src/mention.ts +12 -63
- package/src/oauth.ts +27 -131
- package/src/public/chat.css +191 -143
- package/src/public/chat.html +49 -191
- package/src/public/i18n.js +6 -18
- package/src/public/index.html +46 -1
- package/src/public/settings.html +1 -2
- package/src/public/skills-add.html +0 -8
- package/src/public/studio.html +117 -171
- package/src/public/style.css +150 -260
- package/src/public/subagents-add.html +0 -8
- package/src/router.ts +0 -11
- package/src/store.ts +0 -14
- package/src/subagent.ts +6 -203
- package/src/tools.ts +18 -117
- package/src/trajectory.ts +5 -51
- package/src/usage.ts +0 -10
- package/vendor/protocol/src/index.ts +1 -4
- package/src/public/buddy.js +0 -432
package/src/public/chat.html
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
<link rel="icon" href="/favicon-32.png" type="image/png" sizes="32x32" />
|
|
9
9
|
<link rel="icon" href="/favicon-16.png" type="image/png" sizes="16x16" />
|
|
10
10
|
<title>Guild — 大廳</title>
|
|
11
|
-
<link rel="stylesheet" href="/chat.css?v=
|
|
11
|
+
<link rel="stylesheet" href="/chat.css?v=press-enamel" />
|
|
12
12
|
<script src="/i18n.js"></script>
|
|
13
13
|
<script src="/md.js"></script>
|
|
14
14
|
</head>
|
|
@@ -192,10 +192,9 @@
|
|
|
192
192
|
<div class="traj-bar">
|
|
193
193
|
<strong data-i18n="trace">Trajectory</strong>
|
|
194
194
|
<span class="traj-src" id="traj-src"></span>
|
|
195
|
-
<input id="traj-q" placeholder="搜尋 system / tool /
|
|
195
|
+
<input id="traj-q" placeholder="搜尋 system / tool / 結果" data-i18n-placeholder="search.traj" autocomplete="off" />
|
|
196
196
|
<button type="button" class="traj-close" id="traj-close" aria-label="關閉" data-i18n-aria="close">×</button>
|
|
197
197
|
</div>
|
|
198
|
-
<div class="traj-kinds" id="traj-kinds"></div>
|
|
199
198
|
<div class="traj-main">
|
|
200
199
|
<div class="traj-list" id="traj-list"></div>
|
|
201
200
|
<div class="traj-detail" id="traj-detail"></div>
|
|
@@ -342,26 +341,6 @@
|
|
|
342
341
|
const glyph = Array.from(String(name).replace(/\s+/g, ""))[0] || "?";
|
|
343
342
|
return glyph;
|
|
344
343
|
}
|
|
345
|
-
function portraitUrl(bot) {
|
|
346
|
-
const p = bot && typeof bot.portrait === "string" ? bot.portrait.trim() : "";
|
|
347
|
-
return p.indexOf("/generated/") === 0 ? p : "";
|
|
348
|
-
}
|
|
349
|
-
function avatarFace(bot, name) {
|
|
350
|
-
const url = portraitUrl(bot);
|
|
351
|
-
if (url) return '<img alt="" src="' + escapeHtml(url) + '">';
|
|
352
|
-
return escapeHtml(initials((bot && bot.name) || name || "?"));
|
|
353
|
-
}
|
|
354
|
-
function avatarClass(bot, extra) {
|
|
355
|
-
return (extra || "avatar") + (portraitUrl(bot) ? " has-photo" : "");
|
|
356
|
-
}
|
|
357
|
-
function paintAvatarEl(el, bot) {
|
|
358
|
-
if (!el) return;
|
|
359
|
-
const url = portraitUrl(bot);
|
|
360
|
-
el.classList.toggle("has-photo", Boolean(url));
|
|
361
|
-
el.style.background = bot ? hue(bot.handle) : "#333";
|
|
362
|
-
if (url) el.innerHTML = '<img alt="" src="' + escapeHtml(url) + '">';
|
|
363
|
-
else el.textContent = bot ? initials(bot.name) : "?";
|
|
364
|
-
}
|
|
365
344
|
function escapeHtml(value) {
|
|
366
345
|
return String(value)
|
|
367
346
|
.replace(/&/g, "&")
|
|
@@ -410,7 +389,7 @@
|
|
|
410
389
|
if (name === "read") return t("read");
|
|
411
390
|
if (name === "write") return t("write");
|
|
412
391
|
if (name === "list") return t("list");
|
|
413
|
-
if (name === "spawn"
|
|
392
|
+
if (name === "spawn") return t("spawn");
|
|
414
393
|
return name || "Tool";
|
|
415
394
|
}
|
|
416
395
|
function parseExitCode(output) {
|
|
@@ -566,7 +545,6 @@
|
|
|
566
545
|
usage.input || usage.output
|
|
567
546
|
? t("stats.inOut", {
|
|
568
547
|
in: formatCount(usage.input || 0),
|
|
569
|
-
cache: formatCount(usage.cacheRead || 0),
|
|
570
548
|
out: formatCount(usage.output || 0),
|
|
571
549
|
})
|
|
572
550
|
: usage.estimated
|
|
@@ -712,7 +690,7 @@
|
|
|
712
690
|
error: err,
|
|
713
691
|
});
|
|
714
692
|
}
|
|
715
|
-
if (part.name === "spawn"
|
|
693
|
+
if (part.name === "spawn") {
|
|
716
694
|
return disclosureRow({
|
|
717
695
|
title: t("spawn"),
|
|
718
696
|
icon: iconWrench(),
|
|
@@ -1312,12 +1290,10 @@
|
|
|
1312
1290
|
const stack = bots
|
|
1313
1291
|
.map(
|
|
1314
1292
|
(bot) =>
|
|
1315
|
-
'<span class="' +
|
|
1316
|
-
avatarClass(bot) +
|
|
1317
|
-
'" style="background:' +
|
|
1293
|
+
'<span class="avatar" style="background:' +
|
|
1318
1294
|
hue(bot.handle) +
|
|
1319
1295
|
'">' +
|
|
1320
|
-
|
|
1296
|
+
escapeHtml(initials(bot.name)) +
|
|
1321
1297
|
"</span>",
|
|
1322
1298
|
)
|
|
1323
1299
|
.join("");
|
|
@@ -1412,12 +1388,10 @@
|
|
|
1412
1388
|
href: "#d/" + encodeURIComponent(bot.id),
|
|
1413
1389
|
on: state.kind === "dm" && state.id === bot.id,
|
|
1414
1390
|
av:
|
|
1415
|
-
'<span class="' +
|
|
1416
|
-
avatarClass(bot) +
|
|
1417
|
-
'" style="background:' +
|
|
1391
|
+
'<span class="avatar" style="background:' +
|
|
1418
1392
|
hue(bot.handle) +
|
|
1419
1393
|
'">' +
|
|
1420
|
-
|
|
1394
|
+
escapeHtml(initials(bot.name)) +
|
|
1421
1395
|
"</span>",
|
|
1422
1396
|
name: bot.name,
|
|
1423
1397
|
updatedAt: bot.updatedAt,
|
|
@@ -1447,14 +1421,12 @@
|
|
|
1447
1421
|
? '<span class="meta">' + t("members.addDisabled") + "</span>"
|
|
1448
1422
|
: "";
|
|
1449
1423
|
return (
|
|
1450
|
-
'<div class="members-row"><button type="button" class="' +
|
|
1451
|
-
avatarClass(bot, "avatar sm") +
|
|
1452
|
-
'" data-bot-id="' +
|
|
1424
|
+
'<div class="members-row"><button type="button" class="avatar sm" data-bot-id="' +
|
|
1453
1425
|
escapeHtml(bot.id) +
|
|
1454
1426
|
'" style="background:' +
|
|
1455
1427
|
hue(bot.handle) +
|
|
1456
1428
|
'">' +
|
|
1457
|
-
|
|
1429
|
+
escapeHtml(initials(bot.name)) +
|
|
1458
1430
|
'</button><span class="who"><strong>' +
|
|
1459
1431
|
escapeHtml(bot.name) +
|
|
1460
1432
|
"</strong><em>@" +
|
|
@@ -1473,8 +1445,9 @@
|
|
|
1473
1445
|
document.getElementById("subtitle").textContent = "";
|
|
1474
1446
|
wrap.hidden = true;
|
|
1475
1447
|
document.getElementById("members-pop").hidden = true;
|
|
1448
|
+
av.textContent = bot ? initials(bot.name) : "?";
|
|
1449
|
+
av.style.background = bot ? hue(bot.handle) : "#333";
|
|
1476
1450
|
av.classList.remove("hash-av");
|
|
1477
|
-
paintAvatarEl(av, bot);
|
|
1478
1451
|
if (bot) {
|
|
1479
1452
|
av.setAttribute("href", "#");
|
|
1480
1453
|
av.setAttribute("data-bot-id", bot.id);
|
|
@@ -1494,8 +1467,6 @@
|
|
|
1494
1467
|
const members = ch ? ch.members || [] : [];
|
|
1495
1468
|
const locked = isGeneralChannel(ch);
|
|
1496
1469
|
document.getElementById("subtitle").textContent = "";
|
|
1497
|
-
av.classList.remove("has-photo");
|
|
1498
|
-
av.innerHTML = "";
|
|
1499
1470
|
av.textContent = "#";
|
|
1500
1471
|
av.style.background = "";
|
|
1501
1472
|
av.classList.add("hash-av");
|
|
@@ -1506,12 +1477,10 @@
|
|
|
1506
1477
|
document.getElementById("members-stack").innerHTML = shown
|
|
1507
1478
|
.map(
|
|
1508
1479
|
(bot) =>
|
|
1509
|
-
'<span class="' +
|
|
1510
|
-
avatarClass(bot) +
|
|
1511
|
-
'" style="background:' +
|
|
1480
|
+
'<span class="avatar" style="background:' +
|
|
1512
1481
|
hue(bot.handle) +
|
|
1513
1482
|
'">' +
|
|
1514
|
-
|
|
1483
|
+
escapeHtml(initials(bot.name)) +
|
|
1515
1484
|
"</span>",
|
|
1516
1485
|
)
|
|
1517
1486
|
.join("");
|
|
@@ -1648,16 +1617,14 @@
|
|
|
1648
1617
|
const botAttr = ' data-bot-id="' + escapeHtml(bot.id) + '"';
|
|
1649
1618
|
return {
|
|
1650
1619
|
av:
|
|
1651
|
-
'<button type="button" class="' +
|
|
1652
|
-
avatarClass(bot) +
|
|
1653
|
-
'"' +
|
|
1620
|
+
'<button type="button" class="avatar"' +
|
|
1654
1621
|
botAttr +
|
|
1655
1622
|
' title="' +
|
|
1656
1623
|
escapeHtml(bot.name) +
|
|
1657
1624
|
'" style="background:' +
|
|
1658
1625
|
hue(bot.handle) +
|
|
1659
1626
|
'">' +
|
|
1660
|
-
|
|
1627
|
+
escapeHtml(initials(bot.name)) +
|
|
1661
1628
|
"</button>",
|
|
1662
1629
|
head:
|
|
1663
1630
|
'<div class="msg-head"><button type="button" class="name"' +
|
|
@@ -1944,9 +1911,8 @@
|
|
|
1944
1911
|
fromBottom <= root.clientHeight + 80;
|
|
1945
1912
|
const rows = threadMessages();
|
|
1946
1913
|
if (!rows.length && !currentRoomBusy()) {
|
|
1947
|
-
root.innerHTML =
|
|
1948
|
-
|
|
1949
|
-
: setupThreadHtml();
|
|
1914
|
+
root.innerHTML =
|
|
1915
|
+
'<div class="empty-thread">' + t("noMessages") + "</div>";
|
|
1950
1916
|
syncThreadChrome();
|
|
1951
1917
|
return;
|
|
1952
1918
|
}
|
|
@@ -2047,27 +2013,16 @@
|
|
|
2047
2013
|
const botAttr = bot
|
|
2048
2014
|
? ' data-bot-id="' + escapeHtml(bot.id) + '"'
|
|
2049
2015
|
: "";
|
|
2050
|
-
const av =
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
avatarFace(bot, name) +
|
|
2061
|
-
"</button>"
|
|
2062
|
-
: '<button type="button" class="avatar"' +
|
|
2063
|
-
botAttr +
|
|
2064
|
-
' title="' +
|
|
2065
|
-
escapeHtml(name) +
|
|
2066
|
-
'" style="background:' +
|
|
2067
|
-
hue(handle || name) +
|
|
2068
|
-
'">' +
|
|
2069
|
-
escapeHtml(initials(name)) +
|
|
2070
|
-
"</button>";
|
|
2016
|
+
const av =
|
|
2017
|
+
'<button type="button" class="avatar"' +
|
|
2018
|
+
botAttr +
|
|
2019
|
+
' title="' +
|
|
2020
|
+
escapeHtml(name) +
|
|
2021
|
+
'" style="background:' +
|
|
2022
|
+
hue(handle || name) +
|
|
2023
|
+
'">' +
|
|
2024
|
+
escapeHtml(initials(name)) +
|
|
2025
|
+
"</button>";
|
|
2071
2026
|
const head =
|
|
2072
2027
|
'<div class="msg-head"><button type="button" class="name"' +
|
|
2073
2028
|
botAttr +
|
|
@@ -2300,12 +2255,10 @@
|
|
|
2300
2255
|
bots
|
|
2301
2256
|
.map(
|
|
2302
2257
|
(bot) =>
|
|
2303
|
-
'<span class="' +
|
|
2304
|
-
avatarClass(bot, "queue-av") +
|
|
2305
|
-
'" style="background:' +
|
|
2258
|
+
'<span class="queue-av" style="background:' +
|
|
2306
2259
|
hue(bot.handle) +
|
|
2307
2260
|
'">' +
|
|
2308
|
-
|
|
2261
|
+
escapeHtml(initials(bot.name)) +
|
|
2309
2262
|
"</span>",
|
|
2310
2263
|
)
|
|
2311
2264
|
.join("") +
|
|
@@ -2876,7 +2829,8 @@
|
|
|
2876
2829
|
}
|
|
2877
2830
|
function showBotCard(bot, anchor) {
|
|
2878
2831
|
if (!bot || !anchor) return;
|
|
2879
|
-
|
|
2832
|
+
document.getElementById("bot-card-av").textContent = initials(bot.name);
|
|
2833
|
+
document.getElementById("bot-card-av").style.background = hue(bot.handle);
|
|
2880
2834
|
document.getElementById("bot-card-name").textContent = bot.name;
|
|
2881
2835
|
document.getElementById("bot-card-handle").textContent = "@" + bot.handle;
|
|
2882
2836
|
document.getElementById("bot-card-bio").textContent =
|
|
@@ -4524,12 +4478,10 @@
|
|
|
4524
4478
|
return (
|
|
4525
4479
|
'<button type="button" data-assign="' +
|
|
4526
4480
|
escapeHtml(bot.id) +
|
|
4527
|
-
'"><span class="' +
|
|
4528
|
-
avatarClass(bot, "avatar sm") +
|
|
4529
|
-
'" style="background:' +
|
|
4481
|
+
'"><span class="avatar sm" style="background:' +
|
|
4530
4482
|
hue(bot.handle) +
|
|
4531
4483
|
'">' +
|
|
4532
|
-
|
|
4484
|
+
escapeHtml(initials(bot.name)) +
|
|
4533
4485
|
'</span><span class="assign-copy"><strong>' +
|
|
4534
4486
|
escapeHtml(bot.name) +
|
|
4535
4487
|
"</strong><span>@" +
|
|
@@ -4757,7 +4709,6 @@
|
|
|
4757
4709
|
name: bot.name,
|
|
4758
4710
|
hint: "@" + bot.handle,
|
|
4759
4711
|
glyph: initials(bot.name),
|
|
4760
|
-
photo: portraitUrl(bot),
|
|
4761
4712
|
color: hue(bot.handle),
|
|
4762
4713
|
outside: false,
|
|
4763
4714
|
})),
|
|
@@ -4769,7 +4720,6 @@
|
|
|
4769
4720
|
? t("members.full", { max: CHANNEL_ROSTER_CAP })
|
|
4770
4721
|
: "@" + bot.handle,
|
|
4771
4722
|
glyph: initials(bot.name),
|
|
4772
|
-
photo: portraitUrl(bot),
|
|
4773
4723
|
color: hue(bot.handle),
|
|
4774
4724
|
outside: true,
|
|
4775
4725
|
})),
|
|
@@ -4791,10 +4741,6 @@
|
|
|
4791
4741
|
function pickerItemHtml(row, index, selected) {
|
|
4792
4742
|
const on = index === selected ? " on" : "";
|
|
4793
4743
|
const avStyle = row.color ? "background:" + row.color : "";
|
|
4794
|
-
const photo = row.photo ? String(row.photo) : "";
|
|
4795
|
-
const glyphInner = photo
|
|
4796
|
-
? '<img alt="" src="' + escapeHtml(photo) + '">'
|
|
4797
|
-
: escapeHtml(row.glyph);
|
|
4798
4744
|
const badge = row.badge
|
|
4799
4745
|
? '<span class="out">' + escapeHtml(row.badge) + "</span>"
|
|
4800
4746
|
: row.outside
|
|
@@ -4805,12 +4751,10 @@
|
|
|
4805
4751
|
on +
|
|
4806
4752
|
'" data-mention="' +
|
|
4807
4753
|
index +
|
|
4808
|
-
'"><span class="mention-glyph' +
|
|
4809
|
-
(photo ? " has-photo" : "") +
|
|
4810
|
-
'" style="' +
|
|
4754
|
+
'"><span class="mention-glyph" style="' +
|
|
4811
4755
|
avStyle +
|
|
4812
4756
|
'">' +
|
|
4813
|
-
|
|
4757
|
+
escapeHtml(row.glyph) +
|
|
4814
4758
|
"</span><span><strong>" +
|
|
4815
4759
|
escapeHtml(row.name) +
|
|
4816
4760
|
"</strong><em>" +
|
|
@@ -5210,31 +5154,6 @@
|
|
|
5210
5154
|
if (kind === "oauth") return { mark: "⌁", tone: "" };
|
|
5211
5155
|
return { mark: "●", tone: "" };
|
|
5212
5156
|
}
|
|
5213
|
-
function hallHasModel() {
|
|
5214
|
-
return allModels().some((row) => row.ready);
|
|
5215
|
-
}
|
|
5216
|
-
function setupThreadHtml() {
|
|
5217
|
-
return (
|
|
5218
|
-
'<div class="empty-thread setup-thread">' +
|
|
5219
|
-
'<p class="setup-kicker">' +
|
|
5220
|
-
t("setup.kicker") +
|
|
5221
|
-
"</p>" +
|
|
5222
|
-
'<p class="setup-title">' +
|
|
5223
|
-
t("setup.needModel") +
|
|
5224
|
-
"</p>" +
|
|
5225
|
-
'<p class="setup-body">' +
|
|
5226
|
-
t("setup.needModelBody") +
|
|
5227
|
-
"</p>" +
|
|
5228
|
-
'<p class="setup-acts">' +
|
|
5229
|
-
'<a href="/settings/subs">' +
|
|
5230
|
-
t("setup.subs") +
|
|
5231
|
-
"</a>" +
|
|
5232
|
-
'<a href="/settings/keys">' +
|
|
5233
|
-
t("setup.keys") +
|
|
5234
|
-
"</a>" +
|
|
5235
|
-
"</p></div>"
|
|
5236
|
-
);
|
|
5237
|
-
}
|
|
5238
5157
|
function allModels() {
|
|
5239
5158
|
const rows = [];
|
|
5240
5159
|
for (const p of modelCfg.picker || []) {
|
|
@@ -5415,7 +5334,6 @@
|
|
|
5415
5334
|
modelCfg = await fetch("/settings/models").then((r) => r.json());
|
|
5416
5335
|
renderModelList();
|
|
5417
5336
|
renderNav();
|
|
5418
|
-
if (!(state.messages || []).length && !currentRoomBusy()) renderThread();
|
|
5419
5337
|
}
|
|
5420
5338
|
async function applyChatModel(ref) {
|
|
5421
5339
|
if (state.kind !== "dm") return;
|
|
@@ -5520,7 +5438,6 @@
|
|
|
5520
5438
|
let trajFollow = true;
|
|
5521
5439
|
let trajLive = false;
|
|
5522
5440
|
let trajFetch = 0;
|
|
5523
|
-
let trajKind = "";
|
|
5524
5441
|
function trajUrl() {
|
|
5525
5442
|
return state.kind === "dm"
|
|
5526
5443
|
? "/dms/" + encodeURIComponent(state.id) + "/trajectory"
|
|
@@ -5547,62 +5464,6 @@
|
|
|
5547
5464
|
if (bot) return bot.name + " @" + bot.handle;
|
|
5548
5465
|
return event.botId;
|
|
5549
5466
|
}
|
|
5550
|
-
function trajKindLabel(kind) {
|
|
5551
|
-
if (kind === "spawn") return t("spawn");
|
|
5552
|
-
if (kind === "skill") return t("skill");
|
|
5553
|
-
return String(kind || "").toUpperCase();
|
|
5554
|
-
}
|
|
5555
|
-
function trajKindAliases(kind) {
|
|
5556
|
-
if (kind === "spawn") {
|
|
5557
|
-
return "spawn subagent sub-agent sub agent 子代理";
|
|
5558
|
-
}
|
|
5559
|
-
return "";
|
|
5560
|
-
}
|
|
5561
|
-
function trajSpawnCount() {
|
|
5562
|
-
return trajEvents.filter((event) => event.kind === "spawn").length;
|
|
5563
|
-
}
|
|
5564
|
-
function paintTrajSrc() {
|
|
5565
|
-
const src = document.getElementById("traj-src");
|
|
5566
|
-
const base = src.dataset.base || t("trace.log");
|
|
5567
|
-
const n = trajSpawnCount();
|
|
5568
|
-
const spawnBit = n ? " · " + n + " " + t("spawn") : "";
|
|
5569
|
-
src.textContent =
|
|
5570
|
-
(trajLive ? t("trace.live") + " · " : "") + base + spawnBit;
|
|
5571
|
-
src.classList.toggle("live", trajLive);
|
|
5572
|
-
}
|
|
5573
|
-
function renderTrajKinds() {
|
|
5574
|
-
const el = document.getElementById("traj-kinds");
|
|
5575
|
-
const counts = {};
|
|
5576
|
-
trajEvents.forEach((event) => {
|
|
5577
|
-
counts[event.kind] = (counts[event.kind] || 0) + 1;
|
|
5578
|
-
});
|
|
5579
|
-
const keys = ["", "spawn", "tool", "skill", "thinking", "assistant"];
|
|
5580
|
-
el.innerHTML = keys
|
|
5581
|
-
.map((kind) => {
|
|
5582
|
-
const n = kind ? counts[kind] || 0 : trajEvents.length;
|
|
5583
|
-
const label = kind ? trajKindLabel(kind) : t("trace.filter.all");
|
|
5584
|
-
return (
|
|
5585
|
-
'<button type="button" class="traj-filter' +
|
|
5586
|
-
(kind === "spawn" ? " spawn" : "") +
|
|
5587
|
-
(trajKind === kind ? " on" : "") +
|
|
5588
|
-
'" data-kind="' +
|
|
5589
|
-
escapeHtml(kind) +
|
|
5590
|
-
'">' +
|
|
5591
|
-
escapeHtml(label) +
|
|
5592
|
-
" " +
|
|
5593
|
-
n +
|
|
5594
|
-
"</button>"
|
|
5595
|
-
);
|
|
5596
|
-
})
|
|
5597
|
-
.join("");
|
|
5598
|
-
el.querySelectorAll("[data-kind]").forEach((btn) => {
|
|
5599
|
-
btn.addEventListener("click", () => {
|
|
5600
|
-
trajKind = btn.getAttribute("data-kind") || "";
|
|
5601
|
-
trajFollow = true;
|
|
5602
|
-
renderTrajList();
|
|
5603
|
-
});
|
|
5604
|
-
});
|
|
5605
|
-
}
|
|
5606
5467
|
function renderTrajDetail(event) {
|
|
5607
5468
|
const el = document.getElementById("traj-detail");
|
|
5608
5469
|
if (!event) {
|
|
@@ -5617,7 +5478,7 @@
|
|
|
5617
5478
|
: "";
|
|
5618
5479
|
el.innerHTML =
|
|
5619
5480
|
"<h3>" +
|
|
5620
|
-
escapeHtml(
|
|
5481
|
+
escapeHtml(String(event.kind || "").toUpperCase()) +
|
|
5621
5482
|
"</h3><p class='meta'>" +
|
|
5622
5483
|
escapeHtml(
|
|
5623
5484
|
[trajActorLabel(event), when, "turn " + (event.turnId || "")]
|
|
@@ -5638,15 +5499,11 @@
|
|
|
5638
5499
|
: "");
|
|
5639
5500
|
}
|
|
5640
5501
|
function renderTrajList() {
|
|
5641
|
-
renderTrajKinds();
|
|
5642
5502
|
const q = document.getElementById("traj-q").value.trim().toLowerCase();
|
|
5643
5503
|
const rows = trajEvents.filter((event) => {
|
|
5644
|
-
if (trajKind && event.kind !== trajKind) return false;
|
|
5645
5504
|
if (!q) return true;
|
|
5646
5505
|
const hay = [
|
|
5647
5506
|
event.kind,
|
|
5648
|
-
trajKindLabel(event.kind),
|
|
5649
|
-
trajKindAliases(event.kind),
|
|
5650
5507
|
trajActor(event),
|
|
5651
5508
|
trajActorLabel(event),
|
|
5652
5509
|
event.botId || "",
|
|
@@ -5677,12 +5534,10 @@
|
|
|
5677
5534
|
? Array.from(String(bot.name || bot.handle || "?").trim())[0] || "?"
|
|
5678
5535
|
: Array.from(t("you"))[0] || "?";
|
|
5679
5536
|
const av = bot
|
|
5680
|
-
? '<span class="' +
|
|
5681
|
-
avatarClass(bot, "traj-av") +
|
|
5682
|
-
'" style="background:' +
|
|
5537
|
+
? '<span class="traj-av" style="background:' +
|
|
5683
5538
|
hue(bot.handle) +
|
|
5684
5539
|
'">' +
|
|
5685
|
-
|
|
5540
|
+
escapeHtml(glyph) +
|
|
5686
5541
|
"</span>"
|
|
5687
5542
|
: '<span class="traj-av you">' + escapeHtml(glyph) + "</span>";
|
|
5688
5543
|
return (
|
|
@@ -5699,7 +5554,7 @@
|
|
|
5699
5554
|
'</span><span class="traj-kind ' +
|
|
5700
5555
|
escapeHtml(event.kind) +
|
|
5701
5556
|
'">' +
|
|
5702
|
-
escapeHtml(
|
|
5557
|
+
escapeHtml(String(event.kind || "").toUpperCase()) +
|
|
5703
5558
|
'</span><span class="sum">' +
|
|
5704
5559
|
escapeHtml(event.summary || "") +
|
|
5705
5560
|
"</span></button>"
|
|
@@ -5734,7 +5589,10 @@
|
|
|
5734
5589
|
trajLive = liveRows.length > 0;
|
|
5735
5590
|
if (trajFollow) trajSel = Math.max(0, trajEvents.length - 1);
|
|
5736
5591
|
else if (!trajEvents[trajSel]) trajSel = Math.max(0, trajEvents.length - 1);
|
|
5737
|
-
|
|
5592
|
+
const src = document.getElementById("traj-src");
|
|
5593
|
+
const base = src.dataset.base || t("trace.log");
|
|
5594
|
+
src.textContent = trajLive ? t("trace.live") + " · " + base : base;
|
|
5595
|
+
src.classList.toggle("live", trajLive);
|
|
5738
5596
|
renderTrajList();
|
|
5739
5597
|
}
|
|
5740
5598
|
async function refreshTraj(opts) {
|
|
@@ -5751,7 +5609,10 @@
|
|
|
5751
5609
|
if (trajFollow) trajSel = Math.max(0, trajEvents.length - 1);
|
|
5752
5610
|
else if (!trajEvents[trajSel]) trajSel = Math.max(0, trajEvents.length - 1);
|
|
5753
5611
|
src.dataset.base = trajSourceLabel(body.source);
|
|
5754
|
-
|
|
5612
|
+
src.textContent = trajLive
|
|
5613
|
+
? t("trace.live") + " · " + src.dataset.base
|
|
5614
|
+
: src.dataset.base;
|
|
5615
|
+
src.classList.toggle("live", trajLive);
|
|
5755
5616
|
renderTrajList();
|
|
5756
5617
|
} catch (err) {
|
|
5757
5618
|
if (gen !== trajFetch || trajEl.hidden) return;
|
|
@@ -5813,10 +5674,7 @@
|
|
|
5813
5674
|
renderAttachSheet();
|
|
5814
5675
|
}
|
|
5815
5676
|
}
|
|
5816
|
-
if (!trajEl.hidden)
|
|
5817
|
-
paintTrajSrc();
|
|
5818
|
-
renderTrajList();
|
|
5819
|
-
}
|
|
5677
|
+
if (!trajEl.hidden) renderTrajList();
|
|
5820
5678
|
syncSendButton();
|
|
5821
5679
|
});
|
|
5822
5680
|
window.addEventListener("hashchange", () => {
|
package/src/public/i18n.js
CHANGED
|
@@ -24,7 +24,7 @@ var I18N_ROWS = [
|
|
|
24
24
|
["search.subagents", "搜尋子代理", "Search subagents"],
|
|
25
25
|
["search.mcp", "搜尋 MCP", "Search MCP"],
|
|
26
26
|
["search.models", "搜尋全部模型", "Search all models"],
|
|
27
|
-
["search.traj", "搜尋 system / tool / spawn /
|
|
27
|
+
["search.traj", "搜尋 system / tool / spawn / 結果", "Search system / tool / spawn / result"],
|
|
28
28
|
["channels", "委託", "Channels"],
|
|
29
29
|
["dms", "密談", "Whispers"],
|
|
30
30
|
["newChannel", "新委託", "New channel"],
|
|
@@ -71,7 +71,7 @@ var I18N_ROWS = [
|
|
|
71
71
|
["stats.rounds", "模型回合", "Agent rounds"],
|
|
72
72
|
["stats.cost", "費用", "Cost"],
|
|
73
73
|
["stats.estimated", "估算", "Estimated"],
|
|
74
|
-
["stats.inOut", "輸入 {in} ·
|
|
74
|
+
["stats.inOut", "輸入 {in} · 輸出 {out}", "in {in} · out {out}"],
|
|
75
75
|
["askAgain", "重新詢問", "Ask again"],
|
|
76
76
|
["send", "送出", "Send"],
|
|
77
77
|
["jumpBottom", "滾到最新", "Jump to latest"],
|
|
@@ -95,11 +95,6 @@ var I18N_ROWS = [
|
|
|
95
95
|
["busy", "忙碌中", "Busy"],
|
|
96
96
|
["unread", "未讀", "Unread"],
|
|
97
97
|
["noMessages", "還沒有紀錄。寫一句話開始。據點裡記得 @handle。", "No log yet. Say something. In a hall, @handle an adventurer."],
|
|
98
|
-
["setup.kicker", "第一步", "Step 1"],
|
|
99
|
-
["setup.needModel", "還沒接模型。Guild 不能想、也不能跑工具。", "No model yet. Guild cannot think or run tools."],
|
|
100
|
-
["setup.needModelBody", "先連接訂閱或填 API key,套用主模型,再回來點名。", "Connect a subscription or paste an API key, apply a default, then come back to @mention someone."],
|
|
101
|
-
["setup.subs", "連接訂閱", "Connect a subscription"],
|
|
102
|
-
["setup.keys", "填 API key", "Add an API key"],
|
|
103
98
|
["dm", "密談", "Whisper"],
|
|
104
99
|
["justNow", "剛剛", "Just now"],
|
|
105
100
|
["minutesAgo", "{n} 分鐘前", "{n} min ago"],
|
|
@@ -145,16 +140,15 @@ var I18N_ROWS = [
|
|
|
145
140
|
["remove", "移除", "Remove"],
|
|
146
141
|
["cancelReply", "取消回覆", "Cancel reply"],
|
|
147
142
|
["replying", "回覆…", "Replying…"],
|
|
148
|
-
["trace", "
|
|
143
|
+
["trace", "Trajectory", "Trajectory"],
|
|
149
144
|
["trace.steps", "步驟", "Steps"],
|
|
150
145
|
["trace.long", "長輸出", "Long output"],
|
|
151
146
|
["trace.pick", "選一筆事件。", "Select an event."],
|
|
152
147
|
["trace.empty", "沒有事件。送一則訊息後會開始記錄。", "No events yet. Send a message to start the log."],
|
|
153
|
-
["trace.log", "
|
|
148
|
+
["trace.log", "append-only log", "append-only log"],
|
|
154
149
|
["trace.derived", "由訊息還原", "rebuilt from messages"],
|
|
155
150
|
["trace.live", "進行中", "in progress"],
|
|
156
151
|
["trace.loading", "讀取中…", "Loading…"],
|
|
157
|
-
["trace.filter.all", "全部", "All"],
|
|
158
152
|
["html.preview", "預覽", "Preview"],
|
|
159
153
|
["html.code", "原始碼", "Code"],
|
|
160
154
|
["html.expand", "放大預覽", "Expand preview"],
|
|
@@ -272,7 +266,7 @@ var I18N_ROWS = [
|
|
|
272
266
|
["library.local", "本機", "Host"],
|
|
273
267
|
["settings.eyebrow", "Hermes-style", "Hermes-style"],
|
|
274
268
|
["settings.title", "模型", "Models"],
|
|
275
|
-
["settings.lede", "
|
|
269
|
+
["settings.lede", "訂閱帳號走 OAuth。API key 可同時掛多家供應商,寫入 ~/.guild/models.json。", "Log in with a subscription. API keys can cover several providers and are written to ~/.guild/models.json."],
|
|
276
270
|
["settings.accounts", "連接帳號", "Accounts"],
|
|
277
271
|
["settings.accountsHint", "用訂閱登入,不必複製金鑰。瀏覽器完成授權後會自動刷新 token。", "Subscription login, no key paste. Tokens refresh after the browser handshake."],
|
|
278
272
|
["settings.connect", "連接", "Connect"],
|
|
@@ -292,7 +286,7 @@ var I18N_ROWS = [
|
|
|
292
286
|
["settings.provider", "供應商", "Provider"],
|
|
293
287
|
["settings.apply", "套用", "Apply"],
|
|
294
288
|
["settings.aux", "輔助模型", "Auxiliary models"],
|
|
295
|
-
["settings.auxHint", "
|
|
289
|
+
["settings.auxHint", "Vision、Web extract、Compression 等每一列都寫出實際模型。跟主模型時仍顯示名稱,不是空白。", "Each row — Vision, web extract, compression, and the rest — shows the model in use. Inherited rows still name the default."],
|
|
296
290
|
["settings.auxReset", "全部改回主模型", "Reset all to default"],
|
|
297
291
|
["settings.useMain", "改回跟主模型", "Follow default"],
|
|
298
292
|
["settings.change", "更改", "Change"],
|
|
@@ -332,8 +326,6 @@ var I18N_ROWS = [
|
|
|
332
326
|
["studio.streetAlt", "Guild 酒館門口", "Guild inn door"],
|
|
333
327
|
["studio.leave", "出門", "Leave"],
|
|
334
328
|
["studio.inn", "酒館", "Inn"],
|
|
335
|
-
["studio.idle", "待命", "idle"],
|
|
336
|
-
["studio.diving", "潛水", "diving"],
|
|
337
329
|
["studio.streetLine", "夜晚的酒館還開著。點那扇門進去。", "The inn is still open. Tap the door."],
|
|
338
330
|
["studio.tonight", "今晚", "Tonight"],
|
|
339
331
|
["studio.hire", "招募冒險者", "Recruit an adventurer"],
|
|
@@ -392,10 +384,6 @@ var I18N_ROWS = [
|
|
|
392
384
|
["studio.vacant", "空位", "Vacant"],
|
|
393
385
|
["studio.vacantLine", "空座位。要招冒險者進來嗎?", "Empty seat. Recruit someone?"],
|
|
394
386
|
["studio.hireChip", "招募", "Hire"],
|
|
395
|
-
["studio.genLook", "生成形象", "Generate look"],
|
|
396
|
-
["studio.genLookBusy", "畫臉中…", "Drawing…"],
|
|
397
|
-
["studio.genLookDone", "新形象好了。", "New look ready."],
|
|
398
|
-
["studio.genLookFail", "生圖失敗。到模型頁接 Grok 訂閱或填金鑰再試。", "Image failed. Connect a Grok subscription or add a key on the models page."],
|
|
399
387
|
["studio.drink", "……今晚在這兒喝酒。", "…drinking here tonight."],
|
|
400
388
|
["studio.notFound", "找不到這名冒險者", "Adventurer not found"],
|
|
401
389
|
["studio.editing", "正在編輯 @{handle} · 勾選只屬於這名冒險者", "Editing @{handle} · skills are only for this adventurer"],
|
package/src/public/index.html
CHANGED
|
@@ -15,7 +15,6 @@
|
|
|
15
15
|
rel="stylesheet"
|
|
16
16
|
/>
|
|
17
17
|
<link rel="stylesheet" href="/style.css" />
|
|
18
|
-
<script src="/buddy.js"></script>
|
|
19
18
|
</head>
|
|
20
19
|
<body class="office-page">
|
|
21
20
|
<header class="appbar">
|
|
@@ -64,7 +63,53 @@
|
|
|
64
63
|
const colors = ["#7c6af7", "#5b8def", "#2ea887", "#e07a3d", "#d4537e"];
|
|
65
64
|
return colors[seedOf(key) % colors.length];
|
|
66
65
|
}
|
|
66
|
+
function px(ctx, x, y, w, h, color) {
|
|
67
|
+
ctx.fillStyle = color;
|
|
68
|
+
ctx.fillRect(x, y, w, h);
|
|
69
|
+
}
|
|
70
|
+
function drawBuddy(canvas, shirt, seed) {
|
|
71
|
+
const ctx = canvas.getContext("2d");
|
|
72
|
+
canvas.width = 16;
|
|
73
|
+
canvas.height = 24;
|
|
74
|
+
ctx.imageSmoothingEnabled = false;
|
|
75
|
+
const skin = ["#f0c8a0", "#e2b184", "#c68642", "#8d5524"][seed % 4];
|
|
76
|
+
const hair = ["#2a1c12", "#c4a35a", "#1a1a1a", "#6b2d3c", "#3c4a6e"][seed % 5];
|
|
77
|
+
const outline = "#1b1510";
|
|
78
|
+
const pants = "#2a3140";
|
|
79
|
+
const style = seed % 3;
|
|
80
|
+
|
|
81
|
+
px(ctx, 4, 12, 8, 7, outline);
|
|
82
|
+
px(ctx, 5, 13, 6, 5, shirt);
|
|
83
|
+
px(ctx, 3, 13, 2, 5, shirt);
|
|
84
|
+
px(ctx, 11, 13, 2, 5, shirt);
|
|
85
|
+
px(ctx, 3, 18, 2, 1, skin);
|
|
86
|
+
px(ctx, 11, 18, 2, 1, skin);
|
|
87
|
+
|
|
88
|
+
px(ctx, 4, 4, 8, 8, outline);
|
|
89
|
+
px(ctx, 5, 5, 6, 6, skin);
|
|
90
|
+
px(ctx, 6, 7, 1, 1, outline);
|
|
91
|
+
px(ctx, 9, 7, 1, 1, outline);
|
|
92
|
+
px(ctx, 7, 9, 2, 1, "#c07070");
|
|
67
93
|
|
|
94
|
+
if (style === 0) {
|
|
95
|
+
px(ctx, 4, 3, 8, 3, hair);
|
|
96
|
+
px(ctx, 4, 5, 2, 3, hair);
|
|
97
|
+
px(ctx, 10, 5, 2, 3, hair);
|
|
98
|
+
} else if (style === 1) {
|
|
99
|
+
px(ctx, 4, 2, 8, 4, hair);
|
|
100
|
+
px(ctx, 3, 5, 2, 4, hair);
|
|
101
|
+
px(ctx, 11, 5, 2, 4, hair);
|
|
102
|
+
} else {
|
|
103
|
+
px(ctx, 5, 2, 6, 2, hair);
|
|
104
|
+
px(ctx, 4, 4, 8, 2, hair);
|
|
105
|
+
px(ctx, 7, 1, 2, 2, hair);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
px(ctx, 5, 19, 3, 4, pants);
|
|
109
|
+
px(ctx, 8, 19, 3, 4, pants);
|
|
110
|
+
px(ctx, 5, 23, 3, 1, outline);
|
|
111
|
+
px(ctx, 8, 23, 3, 1, outline);
|
|
112
|
+
}
|
|
68
113
|
function escapeHtml(value) {
|
|
69
114
|
return String(value)
|
|
70
115
|
.replace(/&/g, "&")
|
package/src/public/settings.html
CHANGED
|
@@ -46,7 +46,6 @@
|
|
|
46
46
|
</header>
|
|
47
47
|
<div class="page-body">
|
|
48
48
|
<p id="flash" class="muted"></p>
|
|
49
|
-
<p class="sub" data-i18n="settings.lede">第一次:先連訂閱或填 API key,再套用主模型。沒有模型就不能用。訂閱走 OAuth;API key 寫入 ~/.guild/models.json。</p>
|
|
50
49
|
|
|
51
50
|
<section class="panel" data-sec-panel="main">
|
|
52
51
|
<h2 data-i18n="settings.main">主模型</h2>
|
|
@@ -77,7 +76,7 @@
|
|
|
77
76
|
<h2 data-i18n="settings.aux">輔助模型</h2>
|
|
78
77
|
<button type="button" class="linkish" id="reset-aux" data-i18n="settings.auxReset">全部改回主模型</button>
|
|
79
78
|
</div>
|
|
80
|
-
<p class="sub" data-i18n="settings.auxHint"
|
|
79
|
+
<p class="sub" data-i18n="settings.auxHint">Vision、Web extract、Compression 等每一列都寫出實際模型。跟主模型時仍顯示名稱,不是空白。</p>
|
|
81
80
|
<div id="aux"></div>
|
|
82
81
|
</section>
|
|
83
82
|
|