import type { Task, TaskContext } from '@agentscope-ai/agentscope/state'; import { Ellipsis, ListX, Loader2, Square, SquareCheck } from 'lucide-react'; import { useState } from 'react'; import { PanelEmpty } from '@/components/panel/PanelEmpty'; import { Badge } from '@/components/ui/badge'; import { Button } from '@/components/ui/button'; import { useTranslation } from '@/i18n/useI18n'; import { cn } from '@/lib/utils'; interface TaskPanelProps { /** * The task context to render. Pass ``null`` when no data is * available yet (renders nothing). */ tasksContext: TaskContext | null; className?: string; } /** * State icon for a single task row. * * @param state - The task's current state. * @returns An icon element sized for inline display. */ function StateIcon({ state }: { state: Task['state'] }) { switch (state) { case 'completed': return ; case 'in_progress': return ; default: return ; } } /** * Filters the task list so that only the last 3 of any leading run of * completed tasks are shown; earlier ones are replaced by a single * ellipsis sentinel. * * @param tasks - The full ordered task array. * @returns An object with the visible task slice and a boolean flag * indicating whether the ellipsis row should be rendered. */ function filterTasksWithEllipsis(tasks: Task[]): { showEllipsis: boolean; visibleTasks: Task[]; } { // Count how many consecutive completed tasks appear at the front. let consecutiveCompleted = 0; for (const task of tasks) { if (task.state === 'completed') { consecutiveCompleted++; } else { break; } } const MAX_VISIBLE_COMPLETED = 3; if (consecutiveCompleted <= MAX_VISIBLE_COMPLETED) { return { showEllipsis: false, visibleTasks: tasks }; } // Discard all but the last MAX_VISIBLE_COMPLETED completed tasks. return { showEllipsis: true, visibleTasks: tasks.slice(consecutiveCompleted - MAX_VISIBLE_COMPLETED), }; } /** * Compact, read-only panel listing the agent's current tasks with * their status and dependency information. * * Each row shows ``#id [icon] subject [← blocked by #x, #y]``. * The panel header displays a progress summary like ``Tasks (3/5)``. * When there are more than 3 leading completed tasks, the earlier ones * are collapsed into a single ``…`` separator row. * * @param tasksContext - The full ``TaskContext`` from ``AgentState``. * ``null`` hides the panel entirely. * @param className - The className * @returns A panel element, or ``null`` when there are no tasks. */ export function TaskPanel({ tasksContext, className }: TaskPanelProps) { const { t } = useTranslation(); const [expanded, setExpanded] = useState(false); if (!tasksContext || tasksContext.tasks.length === 0) { return ( ); } const { tasks } = tasksContext; const completed = tasks.filter((task) => task.state === 'completed').length; const { showEllipsis, visibleTasks } = filterTasksWithEllipsis(tasks); const displayedTasks = expanded ? tasks : visibleTasks; return (
{t('panel.plan.completed', { count: completed })} {t('panel.plan.total', { count: tasks.length })}
    {showEllipsis && !expanded && ( )} {displayedTasks.map((task) => (
  • #{task.id} {task.subject} {task.blocked_by.length > 0 && ( ← {t('task-panel.blockedBy')}{' '} {task.blocked_by.map((id) => `#${id}`).join(', ')} )}
  • ))}
); }