Agent Todos

Affichez le plan d’un agent pendant son travail. Chaque étape passe de backlog à à faire, en cours puis terminé, avec des durées en direct, les échecs et les appels d’outils qui les sous-tendent. Une pastille de statut à placer au-dessus du champ de saisie, des changements de plan visibles et une étape de relecture pour modifier le plan avant son exécution.

Les agents de code comme Claude Code, Codex et Gemini CLI tiennent un plan écrit pendant leur travail, via des outils tels que TodoWrite, update_plan et write_todos. Agent Todos transforme ce plan en une ligne par étape, avec l’étape en cours détaillée (« Running the tests ») et la durée de chacune.

Chaque étape passe de backlog à à faire, en cours, puis terminé, échoué ou annulé. Quand l’agent réécrit son plan, les nouvelles étapes sont mises en évidence, les étapes retirées se replient et une courte note indique ce qui a changé. Une étape échouée garde son motif visible, et les longues séries d’étapes terminées se replient pour que le travail en cours reste à l’écran.

AgentTodosStatus place l’étape en cours et un compteur sur une seule ligne au-dessus du champ de saisie, et AgentTodosReview permet de modifier, réordonner, ajouter et supprimer des étapes avant toute exécution, puis de démarrer avec ⌘↵. Les adaptateurs lisent le format d’outil de chaque agent, y compris une entrée encore en streaming, et Tool Calls peut afficher le travail à l’intérieur de n’importe quelle étape.

  1. Ajouter le registre Pro à components.json

    components.json
    {
      "registries": {
        "@hextaui-pro": {
          "url": "https://hextaui.com/r/pro/{name}.json",
          "headers": {
            "Authorization": "Bearer ${HEXTAUI_PRO_TOKEN}"
          }
        }
      }
    }
  2. Ajouter votre token

    Créez un token sur votre page de compte et placez-le dans .env.local sous le nom HEXTAUI_PRO_TOKEN.

  3. Ajouter le block

    pnpm dlx shadcn@latest add @hextaui-pro/agent-todos

Avec AI SDK

getTodosFromParts lit le dernier appel TodoWrite, update_plan ou write_todos d’un message, même pendant que son entrée est encore en streaming. Affichez la liste dans le message et la pastille de statut au-dessus du champ de saisie.

"use client"

import { useChat } from "@ai-sdk/react"

import { AgentTodos, AgentTodosStatus } from "@/components/blocks/agent-todos/agent-todos"
import { getTodosFromParts } from "@/components/blocks/agent-todos/todos"

export function Chat() {
  const { messages, status } = useChat()
  const busy = status === "submitted" || status === "streaming"
  const last = messages.at(-1)
  const current = last?.role === "assistant" ? getTodosFromParts(last.parts) : null

  return (
    <div className="flex flex-col gap-4">
      {messages.map((message) => {
        const plan = message.role === "assistant" ? getTodosFromParts(message.parts) : null
        return plan ? (
          <AgentTodos
            key={message.id}
            todos={plan.todos}
            explanation={plan.explanation}
            running={busy && message.id === last?.id}
          />
        ) : null
      })}
      {current ? <AgentTodosStatus todos={current.todos} running={busy} /> : null}
    </div>
  )
}

Relire avant d’exécuter

Laissez les utilisateurs modifier, réordonner, ajouter et supprimer des étapes avant le démarrage de l’agent. Run plan ou ⌘↵ renvoie la liste nettoyée.

"use client"

import * as React from "react"

import { AgentTodosReview } from "@/components/blocks/agent-todos/todo-review"
import type { Todo } from "@/components/blocks/agent-todos/todos"

export function PlanApproval({
  proposed,
  onRun,
}: {
  proposed: Todo[]
  onRun: (plan: Todo[]) => void
}) {
  const [draft, setDraft] = React.useState(proposed)

  return <AgentTodosReview todos={draft} onChange={setDraft} onApprove={onRun} />
}

Avec des outils de tâches incrémentaux

Pour les outils qui créent et mettent à jour une tâche à la fois, comme TaskCreate et TaskUpdate de Claude Code, intégrez chaque appel à la liste avec applyTaskEvent.

"use client"

import * as React from "react"

import { AgentTodos } from "@/components/blocks/agent-todos/agent-todos"
import { applyTaskEvent, type TaskEvent, type Todo } from "@/components/blocks/agent-todos/todos"

export function useTaskList() {
  const [todos, setTodos] = React.useState<Todo[]>([])
  const apply = React.useCallback(
    (event: TaskEvent) => setTodos((current) => applyTaskEvent(current, event)),
    []
  )
  return { todos, apply }
}

export function Tasks({ todos, running }: { todos: Todo[]; running: boolean }) {
  return <AgentTodos todos={todos} running={running} />
}

Anatomie

Les parties à composer, de l’extérieur vers l’intérieur.

PartieDescription
AgentTodosLa liste complète avec son en-tête, sa barre de progression, son explication et la note de changement de plan.
AgentTodosStatusUne pastille d’une ligne avec l’étape en cours, qui ouvre la liste dans un popover.
AgentTodosReviewLe plan modifiable affiché avant le démarrage de l’agent.
TodoMarkLa marque de statut seule, pour des mises en page personnalisées.
getTodosFromParts, fromTodoWrite, fromUpdatePlan, fromWriteTodos, applyTaskEventDes adaptateurs du format d’outil de chaque agent vers les éléments Todo.
PropTypePar défaut
todosÉtapes dans l’ordre.
Todo[]–
explanationPourquoi le plan se présente ainsi, affiché sous la barre de progression. Codex l’envoie avec update_plan.
string–
runningIndique si l’agent travaille. Vaut true par défaut tant qu’une étape est en cours.
boolean–
titleLibellé de l’en-tête et nom de la région.
string"Tasks"
collapsiblePermet à l’en-tête de replier la liste.
booleantrue
defaultOpenDémarre ouvert.
booleantrue
foldAfterReplie les étapes terminées en haut dès que la liste dépasse cette taille.
number6
PropTypePar défaut
idIdentifiant stable. Les changements de plan sont détectés par id.
string–
contentCe qu’il faut faire, à l’impératif : « Run the tests ».
string–
activeFormCe qu’il fait, affiché pendant l’exécution : « Running the tests ».
string–
statusLe stade. pending se lit « To do ».
"backlog" | "pending" | "in_progress" | "completed" | "failed" | "cancelled"–
errorAffiché sous une étape échouée.
string–
durationSecondes enregistrées, pour l’historique.
number–
detailsS’ouvre sous l’étape, généralement Tool Calls.
ReactNode–
PropTypePar défaut
todosLa même liste. N’affiche rien lorsqu’elle est vide.
Todo[]–
runningAnime la marque et le shimmer tant que la valeur est true.
boolean–
explanationTransmis à la liste dans le popover.
string–
PropTypePar défaut
todosLe plan proposé.
Todo[]–
onChangeAppelé à chaque modification.
(todos: Todo[]) => void–
onApproveAppelé depuis Run plan ou ⌘↵, avec les étapes vides retirées et le texte nettoyé de ses espaces.
(todos: Todo[]) => void–
onCancelAffiche Cancel et gère Escape.
() => void–
titleTitre.
string"Review the plan"
approveLabelLibellé du bouton.
string"Run plan"

getTodosFromParts(parts)

Renvoie { todos, explanation? } à partir de l’appel TodoWrite, update_plan ou write_todos le plus récent d’un message AI SDK, ou null.

PropTypePar défaut
partsFonctionne avec les parties d’outil statiques et dynamiques, y compris une entrée encore en streaming.
UIMessage["parts"]–

applyTaskEvent(todos, event)

Intègre un appel TaskCreate ou TaskUpdate à la liste. Un statut deleted supprime la tâche.

PropTypePar défaut
eventL’appel, normalisé.
{ type: "create", id, subject, activeForm? } | { type: "update", id, status?, subject?, activeForm? }–
ToucheAction
EnterSpaceOuvre ou replie la liste depuis son en-tête, ou les détails d’une étape.
⌘↵Exécute le plan pendant sa relecture, sauf si vous saisissez du texte dans un autre champ.
EnterEn relecture, ajoute une étape sous l’étape courante.
⌫En relecture, supprime une étape vide et passe à celle du dessus.
⌥↑En relecture, monte l’étape. ⌥↓ la descend.
↑↓En relecture, passe d’une étape à l’autre.
EscAnnule la relecture lorsque onCancel est défini.
  • La liste est une région libellée contenant une liste ordonnée, et le nom de chaque étape inclut son stade, par exemple « Running the tests, In progress ».
  • Une progressbar masquée indique combien d’étapes sont terminées.
  • Le démarrage, la fin et l’échec d’une étape sont annoncés via une région live polie, ainsi que les changements de plan. Les ticks du minuteur ne sont pas annoncés.
  • Le libellé de la pastille de statut indique l’étape en cours et le compteur, et ouvre la liste dans un popover à gestion du focus.
  • Les champs de relecture sont libellés par numéro d’étape, les déplacements sont annoncés (« Moved to step 2 of 5 ») et Enter attend tant qu’une méthode de saisie est en cours de composition.
  • Avec réduction des animations, l’anneau en cours cesse de tourner, les coches apparaissent sans se dessiner et les étapes se mettent en place instantanément.

Construit avec

Les composants HextaUI gratuits dont Agent Todos est constitué. Chacun s’installe séparément.

Code

4 fichiers, ajoutés à components/blocks/agent-todos.