添加进度面板,优化消息处理逻辑

This commit is contained in:
2026-04-29 16:55:14 +08:00
parent 30d85173ee
commit 2c1afdc97c
6 changed files with 174 additions and 3 deletions
+80 -1
View File
@@ -7,7 +7,9 @@ import { motion } from "framer-motion";
import {
Avatar,
Box,
Chip,
IconButton,
LinearProgress,
Paper,
Stack,
Typography,
@@ -15,7 +17,9 @@ import {
} from "@mui/material";
import type { Theme } from "@mui/material/styles";
import AutoAwesome from "@mui/icons-material/AutoAwesome";
import CheckCircleRounded from "@mui/icons-material/CheckCircleRounded";
import ErrorOutlineRounded from "@mui/icons-material/ErrorOutlineRounded";
import HourglassEmptyRounded from "@mui/icons-material/HourglassEmptyRounded";
import VolumeUpRounded from "@mui/icons-material/VolumeUpRounded";
import PauseRounded from "@mui/icons-material/PauseRounded";
import PlayArrowRounded from "@mui/icons-material/PlayArrowRounded";
@@ -28,7 +32,7 @@ import {
import { ChatInlineChart } from "./ChatInlineChart";
import { ChatToolCallBlock } from "./ChatToolCallBlock";
import markdownStyles from "./GlobalChatboxMarkdown.module.css";
import type { Message, SpeechState } from "./GlobalChatbox.types";
import type { ChatProgress, Message, SpeechState } from "./GlobalChatbox.types";
import { stripMarkdown } from "./GlobalChatbox.utils";
export const TypingIndicator = () => {
@@ -267,6 +271,9 @@ export const ChatMessageItem = React.memo(
: "#475569",
}}
>
{!isUser && !isErrorMessage && message.progress?.length ? (
<ChatProgressPanel progress={message.progress} />
) : null}
{contentSegments.map((segment, segIdx) => {
if (segment.type === "text") {
const text = segment.content.trim();
@@ -424,3 +431,75 @@ export const ChatMessageItem = React.memo(
);
ChatMessageItem.displayName = "ChatMessageItem";
const ChatProgressPanel = ({ progress }: { progress: ChatProgress[] }) => {
const isComplete = progress.some(
(item) => item.phase === "complete" && item.status === "completed",
);
const latestRunning = isComplete
? undefined
: [...progress].reverse().find((item) => item.status === "running");
return (
<Box
sx={{
mb: 1.5,
p: 1.25,
borderRadius: 2.5,
bgcolor: "rgba(99, 102, 241, 0.06)",
border: "1px solid rgba(99, 102, 241, 0.14)",
}}
>
<Stack spacing={1}>
<Stack direction="row" spacing={1} alignItems="center">
<AutoAwesome sx={{ fontSize: 16, color: "primary.main" }} />
<Typography variant="caption" fontWeight={800} color="text.primary">
Agent
</Typography>
{latestRunning ? (
<Chip
size="small"
label={latestRunning.title}
sx={{ height: 20, fontSize: "0.68rem", bgcolor: "rgba(124, 58, 237, 0.08)" }}
/>
) : null}
</Stack>
{latestRunning ? <LinearProgress sx={{ height: 4, borderRadius: 99 }} /> : null}
<Stack spacing={0.7}>
{progress.slice(-5).map((item) => (
<Stack key={item.id} direction="row" spacing={0.8} alignItems="flex-start">
{item.status === "completed" ? (
<CheckCircleRounded sx={{ fontSize: 15, color: "success.main", mt: 0.2 }} />
) : item.status === "error" ? (
<ErrorOutlineRounded sx={{ fontSize: 15, color: "error.main", mt: 0.2 }} />
) : (
<HourglassEmptyRounded sx={{ fontSize: 15, color: "primary.main", mt: 0.2 }} />
)}
<Box sx={{ minWidth: 0 }}>
<Typography variant="caption" color="text.primary" fontWeight={700}>
{item.title}
</Typography>
{item.detail ? (
<Typography
variant="caption"
component="pre"
color="text.secondary"
sx={{
display: "block",
mt: 0.25,
m: 0,
whiteSpace: "pre-wrap",
fontFamily: "inherit",
fontSize: "0.7rem",
}}
>
{item.detail}
</Typography>
) : null}
</Box>
</Stack>
))}
</Stack>
</Stack>
</Box>
);
};