Archived
feat(ui): add rotating catch-up notices
This commit is contained in:
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"@jmfederico/pi-web": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Add friendlier rotating in-progress response notices when opening a chat mid-reply.
|
||||||
@@ -12,6 +12,19 @@ import "./FormattedText";
|
|||||||
const shortTimestampFormatter = new Intl.DateTimeFormat(undefined, { month: "short", day: "numeric", hour: "2-digit", minute: "2-digit" });
|
const shortTimestampFormatter = new Intl.DateTimeFormat(undefined, { month: "short", day: "numeric", hour: "2-digit", minute: "2-digit" });
|
||||||
const fullTimestampFormatter = new Intl.DateTimeFormat(undefined, { dateStyle: "medium", timeStyle: "medium" });
|
const fullTimestampFormatter = new Intl.DateTimeFormat(undefined, { dateStyle: "medium", timeStyle: "medium" });
|
||||||
|
|
||||||
|
const partialStreamNoticeBodies = [
|
||||||
|
"You opened this chat while the assistant was already replying. The complete answer will appear shortly.",
|
||||||
|
"We joined mid-sentence. Holding the curtain until the full reply is ready.",
|
||||||
|
"The assistant started before this tab arrived. We’ll show the full answer when it lands.",
|
||||||
|
"Catching the reply in one piece — no spoilers, no half-answers.",
|
||||||
|
"The tokens are still assembling themselves. Full answer incoming.",
|
||||||
|
"We arrived fashionably late to this response. The complete version will appear soon.",
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
function randomPartialStreamNoticeBody(): string {
|
||||||
|
return partialStreamNoticeBodies[Math.floor(Math.random() * partialStreamNoticeBodies.length)] ?? partialStreamNoticeBodies[0];
|
||||||
|
}
|
||||||
|
|
||||||
function isScrollPosition(value: unknown): value is { index?: number; key?: string; offset: number } {
|
function isScrollPosition(value: unknown): value is { index?: number; key?: string; offset: number } {
|
||||||
return typeof value === "object"
|
return typeof value === "object"
|
||||||
&& value !== null
|
&& value !== null
|
||||||
@@ -49,6 +62,7 @@ export class ChatView extends LitElement {
|
|||||||
private groupedMessagesCache: ChatGroup[] = [];
|
private groupedMessagesCache: ChatGroup[] = [];
|
||||||
private readonly messageMetaCache = new WeakMap<ChatLine, { short: string; full: string }>();
|
private readonly messageMetaCache = new WeakMap<ChatLine, { short: string; full: string }>();
|
||||||
private readonly messageCopyTextCache = new WeakMap<ChatLine, string>();
|
private readonly messageCopyTextCache = new WeakMap<ChatLine, string>();
|
||||||
|
private partialStreamNoticeBody: string | undefined;
|
||||||
private lastScrollTop = 0;
|
private lastScrollTop = 0;
|
||||||
private lastClientHeight = 0;
|
private lastClientHeight = 0;
|
||||||
private touchStartY: number | undefined;
|
private touchStartY: number | undefined;
|
||||||
@@ -79,6 +93,7 @@ export class ChatView extends LitElement {
|
|||||||
|
|
||||||
protected override willUpdate(changed: Map<string, unknown>): void {
|
protected override willUpdate(changed: Map<string, unknown>): void {
|
||||||
if (changed.has("sessionId")) this.openGroupKeys = this.readOpenGroupKeys();
|
if (changed.has("sessionId")) this.openGroupKeys = this.readOpenGroupKeys();
|
||||||
|
if (changed.has("isReceivingPartialStream") || (changed.has("sessionId") && this.isReceivingPartialStream)) this.syncPartialStreamNoticeBody();
|
||||||
if (changed.has("messages")) this.pinnedToBottom = this.pinnedToBottom && (this.didChatHeightChange() || this.isNearBottom());
|
if (changed.has("messages")) this.pinnedToBottom = this.pinnedToBottom && (this.didChatHeightChange() || this.isNearBottom());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,8 +173,8 @@ export class ChatView extends LitElement {
|
|||||||
private renderSessionActivity() {
|
private renderSessionActivity() {
|
||||||
if (this.isReceivingPartialStream) return html`
|
if (this.isReceivingPartialStream) return html`
|
||||||
<aside class="session-activity receiving" aria-live="polite">
|
<aside class="session-activity receiving" aria-live="polite">
|
||||||
<strong>Receiving answer…</strong>
|
<strong>Catching up…</strong>
|
||||||
<span>This session was reconnected mid-response. The answer will appear when complete.</span>
|
<span>${this.currentPartialStreamNoticeBody()}</span>
|
||||||
</aside>
|
</aside>
|
||||||
`;
|
`;
|
||||||
if (!this.isCompacting) return null;
|
if (!this.isCompacting) return null;
|
||||||
@@ -172,6 +187,15 @@ export class ChatView extends LitElement {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private syncPartialStreamNoticeBody(): void {
|
||||||
|
this.partialStreamNoticeBody = this.isReceivingPartialStream ? randomPartialStreamNoticeBody() : undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
private currentPartialStreamNoticeBody(): string {
|
||||||
|
this.partialStreamNoticeBody ??= randomPartialStreamNoticeBody();
|
||||||
|
return this.partialStreamNoticeBody;
|
||||||
|
}
|
||||||
|
|
||||||
private activityState(): string | undefined {
|
private activityState(): string | undefined {
|
||||||
const status = this.status;
|
const status = this.status;
|
||||||
if (status === undefined) return this.activity?.label;
|
if (status === undefined) return this.activity?.label;
|
||||||
|
|||||||
Reference in New Issue
Block a user