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.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Auto‑Splitting AI Agent Tasks and Real‑Time Monitoring with Spring AI + TodoWrite

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 summary

2. 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-flash

Environment 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.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaAgentSpring AITask AutomationSpring Boot 3TodoWriteTool
Spring Full-Stack Practical Cases
Written by

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.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.