feat(webui): improve beta turn completion and streaming UX

This commit is contained in:
ramonpaolo
2026-05-03 22:28:40 +08:00
committed by Xubin Ren
parent 5853d5dfda
commit 76e3f74df7
18 changed files with 850 additions and 28 deletions
+10 -3
View File
@@ -40,6 +40,7 @@ interface ThreadComposerProps {
onSend: (content: string, images?: SendImage[]) => void;
disabled?: boolean;
placeholder?: string;
isStreaming?: boolean;
modelLabel?: string | null;
variant?: "thread" | "hero";
}
@@ -48,6 +49,7 @@ export function ThreadComposer({
onSend,
disabled,
placeholder,
isStreaming = false,
modelLabel = null,
variant = "thread",
}: ThreadComposerProps) {
@@ -58,8 +60,9 @@ export function ThreadComposer({
const fileInputRef = useRef<HTMLInputElement>(null);
const chipRefs = useRef(new Map<string, HTMLButtonElement>());
const isHero = variant === "hero";
const resolvedPlaceholder =
placeholder ?? t("thread.composer.placeholderThread");
const resolvedPlaceholder = isStreaming
? t("thread.composer.placeholderStreaming")
: placeholder ?? t("thread.composer.placeholderThread");
const { images, enqueue, remove, clear, encoding, full } =
useAttachedImages();
@@ -344,7 +347,11 @@ export function ThreadComposer({
canSend && "hover:scale-[1.03] active:scale-95",
)}
>
<ArrowUp className={cn(isHero ? "h-4.5 w-4.5" : "h-4 w-4")} />
{isStreaming ? (
<Loader2 className={cn(isHero ? "h-4.5 w-4.5" : "h-4 w-4", "animate-spin")} />
) : (
<ArrowUp className={cn(isHero ? "h-4.5 w-4.5" : "h-4 w-4")} />
)}
</Button>
</div>
</div>
+4 -2
View File
@@ -39,7 +39,7 @@ export function ThreadShell({
const { t } = useTranslation();
const chatId = session?.chatId ?? null;
const historyKey = session?.key ?? null;
const { messages: historical, loading } = useSessionHistory(historyKey);
const { messages: historical, loading, hasPendingToolCalls } = useSessionHistory(historyKey);
const { client, modelName } = useClient();
const [booting, setBooting] = useState(false);
const pendingFirstRef = useRef<string | null>(null);
@@ -56,7 +56,7 @@ export function ThreadShell({
setMessages,
streamError,
dismissStreamError,
} = useNanobotStream(chatId, initial);
} = useNanobotStream(chatId, initial, hasPendingToolCalls);
const showHeroComposer = messages.length === 0 && !loading;
const pendingAsk = useMemo(() => {
for (let index = messages.length - 1; index >= 0; index -= 1) {
@@ -179,6 +179,7 @@ export function ThreadShell({
<ThreadComposer
onSend={send}
disabled={!chatId}
isStreaming={isStreaming}
placeholder={
showHeroComposer
? t("thread.composer.placeholderHero")
@@ -191,6 +192,7 @@ export function ThreadShell({
<ThreadComposer
onSend={handleWelcomeSend}
disabled={booting}
isStreaming={isStreaming}
placeholder={
booting
? t("thread.composer.placeholderOpening")