open-swe/ui/src/lib/agents/provider/useLiveMarkdownMessageId.ts
Johannes du Plessis 0108d764d9
fix(ui): resolve eslint errors in dashboard components (#1538)
Clears ~83 pre-existing eslint errors in the UI: auto-fixable rules
(array-type, import/order, sort-imports, type-only imports, redundant
assertions/conditions) plus manual fixes for unnecessary conditions and
banned @ts-nocheck directives. The 8 ported components excluded from
tsconfig are now also ignored by eslint so type-aware linting no longer
fails to parse them.

Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
2026-06-15 17:29:38 -07:00

57 lines
1.9 KiB
TypeScript

import { useEffect, useRef, useState } from "react";
import type { Message } from "@/lib/agents/types";
/** How long run-idle must persist before clearing the live markdown target. */
const LIVE_MARKDOWN_CLEAR_MS = 2000;
/**
* Latches the agent message id that should stay in Streamdown "live" mode.
* `stream.isLoading` flickers on lifecycle events between graph steps; this
* keeps markdown streaming until the run has been idle for a beat.
*/
export function useLiveMarkdownMessageId(
visibleMessages: Array<Message>,
streamIsLoading: boolean | undefined,
isStreaming: boolean,
): string | null {
const [liveMessageId, setLiveMessageId] = useState<string | null>(null);
const clearTimerRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);
const runActive = Boolean(streamIsLoading || isStreaming);
useEffect(() => {
if (runActive) {
if (clearTimerRef.current) {
clearTimeout(clearTimerRef.current);
clearTimerRef.current = undefined;
}
const lastMessage = visibleMessages[visibleMessages.length - 1];
// A new user prompt at the tail means the prior agent turn is done — keep it
// static so Streamdown does not re-animate it while waiting for the reply.
if (!lastMessage || lastMessage.author === "user") {
setLiveMessageId(null);
return;
}
if (lastMessage.author === "agent") {
setLiveMessageId((prev) => (prev === lastMessage.id ? prev : lastMessage.id));
}
return;
}
clearTimerRef.current = setTimeout(() => {
clearTimerRef.current = undefined;
setLiveMessageId(null);
}, LIVE_MARKDOWN_CLEAR_MS);
return () => {
if (clearTimerRef.current) {
clearTimeout(clearTimerRef.current);
clearTimerRef.current = undefined;
}
};
}, [runActive, visibleMessages]);
return liveMessageId;
}