Auto‑Splitting AI Agent Tasks and Real‑Time Monitoring with Spring AI + TodoWrite
This article explains how the TodoWriteTool, a Spring AI extension, solves large‑language‑model “mid‑session forgetting” by automatically splitting complex agent tasks into explicit, sequential subtasks and providing real‑time progress monitoring, with a complete Spring Boot 3.5.0 setup, code examples, and a runnable demonstration.
1. Introduction
Large language models often suffer from “mid‑session forgetting”, losing tasks hidden in long context. When an AI agent handles file editing, test execution, and documentation updates simultaneously, steps can be silently omitted. Inspired by Claude Code’s TodoWrite feature, the TodoWriteTool makes task planning explicit and traceable, ensuring the agent never skips a step and the workflow can be monitored in real time.
What is TodoWriteTool?
TodoWriteTool is a Spring AI utility that lets an LLM create, track, and update a todo list during execution. Each todo item has an ID, description, and status, and follows a simple lifecycle.
Agent workflow
When the agent receives a complex request (e.g., add a dark‑mode toggle and run tests), it first calls TodoWriteTool to split the request into subtasks, then executes them sequentially. The tool is invoked for any task‑related operation—creating the initial list, marking progress, or adding ad‑hoc items.
The tool enforces a single‑in‑progress constraint, guaranteeing sequential, focused execution.
Progress: 2/4 tasks completed (50%)</code>
<code>[✓] Find top 10 Tom Hanks movies</code>
<code>[✓] Group movies in pairs</code>
<code>[→] Print inverted titles</code>
<code>[ ] Final summary2. Hands‑on Example
2.1 Prepare environment
Spring Boot 3.5.0 is used. Add the following Maven dependencies:
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-openai</artifactId>
</dependency>
<dependency>
<groupId>org.springaicommunity</groupId>
<artifactId>spring-ai-agent-utils</artifactId>
</dependency>Configure the AI model in application.yml (or application.properties) with OpenAI credentials and model:
spring:
ai:
openai:
api-key: ${API_KEY}
base-url: ${BASE_URL}
chat:
model: deepseek-v4-flashEnvironment ready.
2.2 Configure the Agent
Configure a ChatClient with the TodoWriteTool and advisors:
@RestController
@RequestMapping("/ai/task")
public class AiTaskControler {
private final ChatClient chatClient;
public AiTaskControler(ChatClient.Builder builder, ApplicationContext context) {
this.chatClient = builder
.defaultTools(TodoWriteTool.builder()
.todoEventHandler(event ->
context.publishEvent(new TodoUpdateEvent(this, event.todos())))
.build())
.defaultAdvisors(
ToolCallAdvisor.builder().conversationHistoryEnabled(false).build(),
MessageChatMemoryAdvisor.builder(
MessageWindowChatMemory.builder().maxMessages(500).build()).build())
.build();
}
@GetMapping("/execute")
public String execute() {
String response = chatClient.prompt()
.user("找出周星驰评分最高的 6 部电影,将它们两两分组,并把每部电影的片名倒序拼写输出。使用 TodoWrite 来梳理、规划你的执行任务。")
.advisors(a -> a.param(ChatMemory.CONVERSATION_ID, "C-0001"))
.call()
.content();
return response;
}
}Important: disabling conversationHistoryEnabled(false) turns off the built‑in tool‑call history and delegates context management to MessageChatMemoryAdvisor.
2.3 Event‑driven progress updates
A listener can print progress to the console:
@Component
public class TodoProgressListener {
@EventListener
public void onTodoUpdate(TodoUpdateEvent event) {
System.err.println(event.getTodos());
int completed = (int) event.getTodos().stream()
.filter(t -> t.status() == Todos.Status.completed).count();
int total = event.getTodos().size();
System.out.printf("
Progress: %d/%d tasks completed (%.0f%%)
",
completed, total, completed * 100.0 / total);
}
}The TodoUpdateEvent simply carries a List<TodoItem>:
public class TodoUpdateEvent extends ApplicationEvent {
private final List<TodoItem> todos;
public TodoUpdateEvent(Object source, List<TodoItem> todos) {
super(source);
this.todos = todos;
}
public List<TodoItem> getTodos() { return todos; }
}2.4 Test run
Running the endpoint produces console output showing three subtasks executed in order, with progress updates as illustrated below.
The agent splits the original request into three explicit tasks and processes them sequentially.
End of article.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Spring Full-Stack Practical Cases
Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
