ai-chatbot/components/canvas/chat-panel/canvas-agent-progress.tsx

48 lines
3.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
import { CircleAlert, Check, ChevronDown, Loader2, RotateCcw, Square } from "lucide-react";
import type { AgentRunView } from "@/lib/ai/canvas-agent-runtime/protocol";
import { canvasAgentProgressLabel, type CanvasAgentProgress } from "@/lib/ai/canvas-agent-runtime/progress";
export function CanvasAgentProgressMessage(props: {
progress: CanvasAgentProgress; run?: AgentRunView | null; busy?: boolean;
stopping?: boolean; sending?: boolean; onCancel?: () => void; onResume?: () => void;
}) {
const { progress, run } = props;
const running = progress.status === "running";
const label = progress.status === "completed" ? "处理完成"
: props.stopping && running ? "正在停止后续步骤,已完成的结果会保留"
: canvasAgentProgressLabel(progress.message || "正在处理你的任务");
return (
<div className="my-2 w-full min-w-0 text-xs text-zinc-500 dark:text-zinc-400" data-testid="canvas-agent-progress" data-agent-message-id={run?.assistantMessageId}>
<div className="flex items-start gap-2">
<details className="min-w-0 flex-1" open={running}>
<summary className="flex cursor-pointer list-none items-center gap-2 py-1 [&::-webkit-details-marker]:hidden">
{running ? <Loader2 className="h-3.5 w-3.5 shrink-0 animate-spin" /> : progress.status === "completed" ? <Check className="h-3.5 w-3.5 shrink-0" /> : <CircleAlert className="h-3.5 w-3.5 shrink-0" />}
<span className="min-w-0 flex-1" role="status" aria-live="polite">{label}</span>
<ChevronDown className="h-3 w-3 shrink-0" />
</summary>
{progress.activities?.length ? (
<ol className="ml-1.5 mt-1 space-y-1.5 border-l border-zinc-200 pl-4 dark:border-zinc-800" aria-label="任务执行步骤">
{progress.activities.map(activity => (
<li key={activity.id} className="flex items-center gap-2">
{activity.status === "started" ? <Loader2 className="h-3 w-3 shrink-0 animate-spin" /> : <span className="h-1 w-1 shrink-0 rounded-full bg-current" />}
<span>{canvasAgentProgressLabel(activity.title)}</span>
<span className="text-[11px] opacity-75">{activity.status === "succeeded" ? "已完成" : activity.status === "failed" ? "待处理" : activity.status === "queued" ? "待执行" : "进行中"}</span>
</li>
))}
</ol>
) : null}
{run?.inputs.slice(-2).map(input => (
<p key={input.id} className="mt-2 whitespace-pre-wrap break-words">{input.applied ? "已应用补充要求" : "已收到补充要求"}:{input.text}</p>
))}
</details>
{running && props.onCancel ? (
<button type="button" onClick={props.onCancel} disabled={props.sending || props.stopping} className="rounded-md p-1.5 hover:bg-zinc-100 disabled:opacity-40 dark:hover:bg-white/10" title="停止后续步骤" aria-label="停止后续步骤"><Square className="h-3.5 w-3.5" /></button>
) : run?.resumable && props.onResume ? (
<button type="button" onClick={props.onResume} disabled={props.busy} className="inline-flex shrink-0 items-center gap-1 rounded-md px-2 py-1 hover:bg-zinc-100 disabled:opacity-40 dark:hover:bg-white/10"><RotateCcw className="h-3.5 w-3.5" />继续任务</button>
) : null}
</div>
</div>
);
}