mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-12 21:53:00 -06:00
fix(ui): prevent reading indicator from sticking after assistant response (#83711)
Summary: - The PR removes the Control UI chat fallback that converts a null stream into an empty stream for abortable runs, adds null-vs-empty stream regression tests, and updates the changelog. - Reproducibility: yes. source-level reproduction is high confidence: current main converts null stream plus c ... ading indicator. The linked source PR also reports live Control UI verification after the equivalent patch. Automerge notes: - PR branch already contained follow-up commit before automerge: fix(ui): prevent reading indicator from sticking after assistant resp… Validation: - ClawSweeper review passed for head44bea55110. - Required merge gates passed before the squash merge. Prepared head SHA:44bea55110Review: https://github.com/openclaw/openclaw/pull/83711#issuecomment-4480128171 Co-authored-by: 二狗子 <njuboy11@users.noreply.github.com> Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com> Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com> Approved-by: takhoffman Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
This commit is contained in:
@@ -46,6 +46,7 @@ Docs: https://docs.openclaw.ai
|
||||
### Fixes
|
||||
|
||||
- Agents/image generation: allow distinct `image_generate` prompts to start separate session-backed background tasks while same-prompt retries still return the active task status. (#83614) Thanks @Elarwei001.
|
||||
- Control UI: stop the chat reading indicator from sticking after an assistant response finishes. (#83515) Thanks @njuboy11.
|
||||
- Skills: reject empty or whitespace-only skill names and descriptions during quick validation. (#27061)
|
||||
- Sessions: skip trailing custom transcript entries when checking tail assistant replies so embedded CLI gap-fill does not duplicate canonical assistant output. (#83635) Thanks @yaoyi1222.
|
||||
- Memory Wiki: keep `wiki_lint` tool output path-safe by reporting vault-internal lint reports as relative paths in tool text and details while preserving absolute report paths for CLI/file callers. (#83439) Thanks @LLagoon3.
|
||||
|
||||
@@ -489,14 +489,37 @@ describe("chat loading skeleton", () => {
|
||||
expect(container.querySelector(".agent-chat__welcome")).toBeNull();
|
||||
});
|
||||
|
||||
it("shows the reading indicator instead of the skeleton while an active run has no stream yet", () => {
|
||||
it("shows the loading skeleton for an active run with no stream", () => {
|
||||
const container = renderChatView({ canAbort: true, loading: true });
|
||||
|
||||
expect(container.querySelector(".chat-loading-skeleton")).toBeNull();
|
||||
expect(container.querySelectorAll(".chat-reading-indicator")).toHaveLength(1);
|
||||
expect(container.querySelector(".chat-loading-skeleton")).not.toBeNull();
|
||||
expect(container.querySelectorAll(".chat-reading-indicator")).toHaveLength(0);
|
||||
expect(container.querySelector(".agent-chat__welcome")).toBeNull();
|
||||
});
|
||||
|
||||
it("shows the reading indicator when an active run has an empty stream", () => {
|
||||
const container = renderChatView({ canAbort: true, stream: "" });
|
||||
|
||||
expect(container.querySelector(".chat-reading-indicator")).not.toBeNull();
|
||||
});
|
||||
|
||||
it("does not keep the reading indicator after an assistant response has rendered", () => {
|
||||
const container = renderChatView({
|
||||
canAbort: true,
|
||||
messages: [
|
||||
{
|
||||
role: "assistant",
|
||||
content: "Finished answer",
|
||||
timestamp: 1,
|
||||
},
|
||||
],
|
||||
stream: null,
|
||||
});
|
||||
|
||||
expect(container.querySelector(".chat-reading-indicator")).toBeNull();
|
||||
expect(container.querySelector(".chat-group")?.textContent?.trim()).toBe("Finished answer");
|
||||
});
|
||||
|
||||
it("keeps existing messages visible without the skeleton during a background reload", () => {
|
||||
const container = renderChatView({
|
||||
loading: true,
|
||||
|
||||
@@ -1003,7 +1003,7 @@ export function renderChat(props: ChatProps) {
|
||||
const requestUpdate = props.onRequestUpdate ?? (() => {});
|
||||
const splitRatio = props.splitRatio ?? 0.6;
|
||||
const sidebarOpen = Boolean(props.sidebarOpen && props.onCloseSidebar);
|
||||
const displayStream = props.stream ?? (canAbort ? "" : null);
|
||||
const displayStream = props.stream ?? null;
|
||||
|
||||
const handleCodeBlockCopy = (e: Event) => {
|
||||
const btn = (e.target as HTMLElement).closest(".code-block-copy");
|
||||
|
||||
Reference in New Issue
Block a user