Sagents.Middleware.TodoList (Sagents v0.8.0-rc.6)
Copy MarkdownMiddleware that adds TODO list management capabilities to agents.
Provides the write_todos tool for creating, updating, and managing TODO items
during complex multi-step tasks.
Usage
{:ok, agent} = Agent.new(
model: model,
middleware: [TodoList]
)
# Agent can now use write_todos tool to manage tasksConfiguration
:display_text- Label shown in UI when thewrite_todostool runs. Defaults to"Updating task list". Useful when the todo list is used internally by the agent (e.g. self-organization during an onboarding flow) and the default label would leak implementation detail to users.:inline- Controls how todo updates surface to the UI. Defaults tofalse. See "Display modes" below.
Display modes
Every successful write_todos call produces a state change. Two delivery
channels are available — the choice is purely about where in the UI the
todo list appears:
Default (
inline: false) — only emits the{:todos_updated, todos}event over the AgentServer's broadcast channel. Subscribers (typically a sidebar or status panel in the LiveView) re-render from that snapshot. The chat transcript itself shows nothing about the todo list; the transcript stays focused on the agent's textual reasoning and tool calls. Best when the UI has dedicated "task list" real estate, or when todos are an internal planning detail you don't want surfacing to the end user.Inline (
inline: true) — emits the same{:todos_updated, todos}event and additionally persists a synthetic display message (content_type"todo_snapshot") into the conversation transcript. Each snapshot is a separate message, so the chat shows the plan evolving over time threaded with the agent's other output. Best when there is no sidebar, or when seeing the plan unfold inside the conversation is part of the desired UX.
Inline mode requires the AgentServer to be configured with a
Sagents.DisplayMessagePersistence module that implements
save_synthetic_message/3. Without it the inline-mode call is a silent
no-op (the existing {:todos_updated, _} broadcast still fires).
Usage
# default: only the {:todos_updated, todos} broadcast — sidebar UIs
{:ok, agent} = Agent.new(middleware: [TodoList])
# custom label for a user-facing flow where todos are internal
{:ok, agent} = Agent.new(
middleware: [{TodoList, display_text: "Updating my notes"}]
)
# inline mode: also emit a todo_snapshot display message per update
# so the plan appears inline in the chat transcript
{:ok, agent} = Agent.new(middleware: [{TodoList, inline: true}])
# inline mode + custom label, both options together
{:ok, agent} = Agent.new(
middleware: [{TodoList, inline: true, display_text: "Replanning"}]
)