viberoom 0.5.1 → 0.5.2
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/dist/room.js +5 -3
- package/package.json +1 -1
- package/ui/app.css +15 -1
- package/ui/app.js +36 -11
package/dist/room.js
CHANGED
|
@@ -1660,6 +1660,7 @@ export class Room extends EventEmitter {
|
|
|
1660
1660
|
}
|
|
1661
1661
|
const startedAt = runtime.turn.startedAt;
|
|
1662
1662
|
const published = runtime.turn.published;
|
|
1663
|
+
const publishedAt = runtime.turn.publishedAt ?? null;
|
|
1663
1664
|
runtime.turn = null;
|
|
1664
1665
|
runtime.turnActive = false;
|
|
1665
1666
|
this.drafts.delete(draft.id);
|
|
@@ -1689,9 +1690,9 @@ export class Room extends EventEmitter {
|
|
|
1689
1690
|
this.closeRetry(retry, "the correction turn failed; nothing was posted");
|
|
1690
1691
|
return null;
|
|
1691
1692
|
}
|
|
1692
|
-
return this.finalizeTurn(participant, runtime, draft, result, Date.now() - startedAt, retry, published);
|
|
1693
|
+
return this.finalizeTurn(participant, runtime, draft, result, Date.now() - startedAt, retry, published, publishedAt);
|
|
1693
1694
|
}
|
|
1694
|
-
finalizeTurn(participant, runtime, draft, result, durationMs, retry, published) {
|
|
1695
|
+
finalizeTurn(participant, runtime, draft, result, durationMs, retry, published, publishedAt = null) {
|
|
1695
1696
|
participant.status = "idle";
|
|
1696
1697
|
this.push({ type: "participant", participant });
|
|
1697
1698
|
const text = draft.text.trim();
|
|
@@ -1787,7 +1788,7 @@ export class Room extends EventEmitter {
|
|
|
1787
1788
|
durationMs,
|
|
1788
1789
|
};
|
|
1789
1790
|
this.commit(message);
|
|
1790
|
-
if (this.messages.some((x) => x.kind === "chat" && x.id !== message.id && x.ts >
|
|
1791
|
+
if (publishedAt !== null && this.messages.some((x) => x.kind === "chat" && x.id !== message.id && x.ts > publishedAt)) {
|
|
1791
1792
|
const at = new Date(draft.ts);
|
|
1792
1793
|
const hhmm = `${String(at.getHours()).padStart(2, "0")}:${String(at.getMinutes()).padStart(2, "0")}`;
|
|
1793
1794
|
this.postSystem(`${participant.name} finished the reply started at ${hhmm} · ${Math.round(durationMs / 1000)} s`, "human", false, { refId: message.id, agentId: participant.id });
|
|
@@ -1874,6 +1875,7 @@ export class Room extends EventEmitter {
|
|
|
1874
1875
|
if (turn.published)
|
|
1875
1876
|
return;
|
|
1876
1877
|
turn.published = true;
|
|
1878
|
+
turn.publishedAt = Date.now();
|
|
1877
1879
|
this.push({ type: "message", message: turn.message });
|
|
1878
1880
|
}
|
|
1879
1881
|
onSessionUpdate(id, update) {
|
package/package.json
CHANGED
package/ui/app.css
CHANGED
|
@@ -374,7 +374,20 @@ table.csv tbody tr:nth-child(even) td { background: rgba(91, 91, 240, 0.03); }
|
|
|
374
374
|
.tool { display: inline-flex; flex-direction: column; max-width: 100%; min-width: 0; }
|
|
375
375
|
.tool.open { flex-basis: 100%; }
|
|
376
376
|
.tool > .chip { font: inherit; font-size: 11px; font-weight: 800; cursor: pointer; text-align: left; }
|
|
377
|
-
.tool-
|
|
377
|
+
.tool > .chip-completed { --tool-bg: var(--mint); --tool-ink: var(--mint-ink); }
|
|
378
|
+
.tool > .chip-failed { --tool-bg: var(--rose); --tool-ink: var(--rose-ink); }
|
|
379
|
+
.tool > .chip-in_progress { --tool-bg: var(--warm); --tool-ink: var(--warm-ink); }
|
|
380
|
+
.tool > .chip-pending { --tool-bg: var(--lav); --tool-ink: var(--primary); }
|
|
381
|
+
.tool > .chip::after { content: "▾"; margin-left: auto; padding-left: 8px; opacity: 0.55; transition: transform var(--t-fast); }
|
|
382
|
+
.tool.open > .chip { width: 100%; border-radius: 12px 12px 0 0; padding: 6px 12px; white-space: normal; }
|
|
383
|
+
.tool.open > .chip::after { transform: rotate(180deg); }
|
|
384
|
+
.tool.open { --tool-bg: var(--lav); --tool-ink: var(--primary); }
|
|
385
|
+
.tool.open > .chip-completed ~ .tool-body, .tool.open > .chip-completed + .tool-body { --tool-bg: var(--mint); --tool-ink: var(--mint-ink); }
|
|
386
|
+
.tool.open > .chip-failed + .tool-body { --tool-bg: var(--rose); --tool-ink: var(--rose-ink); }
|
|
387
|
+
.tool.open > .chip-in_progress + .tool-body { --tool-bg: var(--warm); --tool-ink: var(--warm-ink); }
|
|
388
|
+
.tool-body { margin: 0; padding: 8px 10px 10px; background: var(--card); border: 2px solid var(--tool-bg, var(--lav)); border-top: 0; border-radius: 0 0 12px 12px; font-size: 12px; max-height: 340px; overflow: auto; }
|
|
389
|
+
.tool-body pre { background: var(--soft); color: var(--ink); padding: 6px 8px; border-radius: 8px; }
|
|
390
|
+
.tool-sec b { color: var(--tool-ink, var(--muted)); }
|
|
378
391
|
.tool-sec + .tool-sec { margin-top: 8px; }
|
|
379
392
|
.tool-sec b { display: block; font-size: 10.5px; font-weight: 800; letter-spacing: 0.04em; text-transform: uppercase; color: var(--muted); }
|
|
380
393
|
.tool-sec.muted { color: var(--muted); font-style: italic; }
|
|
@@ -582,3 +595,4 @@ table.csv tbody tr:nth-child(even) td { background: rgba(91, 91, 240, 0.03); }
|
|
|
582
595
|
.done-notes { flex-direction: column; }
|
|
583
596
|
.done-note.new { background: var(--card); color: var(--ink-2); }
|
|
584
597
|
.done-note.new:hover { background: var(--soft); }
|
|
598
|
+
.meta .seen-by { color: var(--primary); font-weight: 800; margin-left: 6px; }
|
package/ui/app.js
CHANGED
|
@@ -1417,7 +1417,8 @@
|
|
|
1417
1417
|
if (m.durationMs) parts.push(`<span title="how long the reply took">${ic("clock")} ${(m.durationMs / 1000).toFixed(1)} s</span>`);
|
|
1418
1418
|
if (m.usage) parts.push(`<span title="tokens in">${ic("arrow-down")} ${fmtTokens(m.usage.inputTokens)}</span><span title="tokens out">${ic("arrow-up")} ${fmtTokens(m.usage.outputTokens)}</span>${m.usage.cachedWriteTokens ? `<span title="tokens written to the cache">${ic("database")} ${fmtTokens(m.usage.cachedWriteTokens)}</span>` : ""}`);
|
|
1419
1419
|
meta.innerHTML = parts.join("<span class=\"sep\">·</span>");
|
|
1420
|
-
|
|
1420
|
+
fillSeen(el, room, m);
|
|
1421
|
+
} else if (m.from === "human") fillSeen(el, room, m);
|
|
1421
1422
|
else meta.textContent = "";
|
|
1422
1423
|
}
|
|
1423
1424
|
|
|
@@ -1429,23 +1430,47 @@
|
|
|
1429
1430
|
return null;
|
|
1430
1431
|
}
|
|
1431
1432
|
function seenHtml(room, m) {
|
|
1432
|
-
const present = room.participants.filter((p) => p.kind === "agent" && p.status !== "left" && p.status !== "offline");
|
|
1433
|
+
const present = room.participants.filter((p) => p.kind === "agent" && p.status !== "left" && p.status !== "offline" && p.id !== m.from);
|
|
1434
|
+
if (!present.length) return "";
|
|
1433
1435
|
const seen = present.filter((p) => p.lastSeenSeq != null && p.lastSeenSeq >= m.seq);
|
|
1436
|
+
if (seen.length === present.length) return "";
|
|
1434
1437
|
if (!seen.length) return `<span class="ticks">✓</span> sent`;
|
|
1435
|
-
if (present.length > 1 && seen.length === present.length) return `<span class="ticks">✓✓</span> seen by all`;
|
|
1436
1438
|
return `<span class="ticks">✓✓</span> seen by ${esc(seen.map((p) => p.name).join(", "))}`;
|
|
1437
1439
|
}
|
|
1440
|
+
function fillSeen(el, room, m) {
|
|
1441
|
+
if (m.kind !== "chat" || m.streaming) return;
|
|
1442
|
+
const html = seenHtml(room, m);
|
|
1443
|
+
if (m.from === "human") {
|
|
1444
|
+
const meta = el.querySelector(".meta");
|
|
1445
|
+
if (!meta) return;
|
|
1446
|
+
meta.innerHTML = html;
|
|
1447
|
+
meta.classList.toggle("seen", !!html);
|
|
1448
|
+
} else {
|
|
1449
|
+
const meta = el.querySelector(".meta");
|
|
1450
|
+
let span = meta && meta.querySelector(".seen-by");
|
|
1451
|
+
if (!span && meta && html) {
|
|
1452
|
+
span = document.createElement("span");
|
|
1453
|
+
span.className = "seen-by";
|
|
1454
|
+
meta.appendChild(span);
|
|
1455
|
+
}
|
|
1456
|
+
if (span) {
|
|
1457
|
+
span.innerHTML = html;
|
|
1458
|
+
span.hidden = !html;
|
|
1459
|
+
}
|
|
1460
|
+
}
|
|
1461
|
+
}
|
|
1438
1462
|
function refreshSeen(room) {
|
|
1439
|
-
const
|
|
1463
|
+
const present = room.participants.filter((p) => p.kind === "agent" && p.status !== "left" && p.status !== "offline");
|
|
1464
|
+
const floor = present.length ? Math.min(...present.map((p) => (p.lastSeenSeq == null ? 0 : p.lastSeenSeq))) : Infinity;
|
|
1440
1465
|
const byId = new Map(room.messages.map((m) => [m.id, m]));
|
|
1441
|
-
for (const el of els.messages.querySelectorAll(".msg.mine")) {
|
|
1442
|
-
const
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
meta.innerHTML = isLast ? seenHtml(room, last) : "";
|
|
1446
|
-
meta.classList.toggle("seen", !!isLast);
|
|
1466
|
+
for (const el of els.messages.querySelectorAll(".msg.mine, .msg.agent")) {
|
|
1467
|
+
const seq = Number(el.dataset.seq);
|
|
1468
|
+
const hasLabel = el.querySelector(".meta.seen, .seen-by:not([hidden])");
|
|
1469
|
+
if (seq <= floor && !hasLabel) continue;
|
|
1447
1470
|
const m = byId.get(el.dataset.id);
|
|
1448
|
-
if (m
|
|
1471
|
+
if (!m) continue;
|
|
1472
|
+
fillSeen(el, room, m);
|
|
1473
|
+
if (m.from === "human" && (seq > floor || el.classList.contains("waiting"))) renderWaiting(el, room, m);
|
|
1449
1474
|
}
|
|
1450
1475
|
}
|
|
1451
1476
|
|