Overview
Planning is how an agent breaks a complex request into discrete, ordered, and trackable steps. Instead of letting the model juggle a multi-step goal entirely in free-form reasoning, AgentScope exposes a small set of built-in tools that let the agent maintain an explicit, structured task list — created, queried, and updated through normal tool calls. AgentScope ships four planning tools out of the box:| Tool | Operation | Read-only |
|---|---|---|
TaskCreate | Append a new task to the task list | No |
TaskGet | Retrieve full details (description, status, dependencies) for a single task by ID | Yes |
TaskList | List every task with its status, owner, and blocking relationships | Yes |
TaskUpdate | Update a task’s status, fields, or dependency edges; or delete it | No |
is_state_injected = True): the agent runtime hands each call the live AgentState, and the tools read from / write to agent.state.tasks_context. That means the task list is scoped per agent and persists naturally across reasoning steps, ReAct rounds, and human-in-the-loop pauses, alongside the rest of the agent’s saved state.
Use Plan Tools
Equip the Tools
Instantiate the tools and register them on aToolkit like any other built-in tool:
description already contains a detailed prompt describing when to call it, when to skip it, and how to interpret its output, so no additional system-prompt engineering is required. check_permissions() is hard-wired to ALLOW — the planning tools are pure in-memory state mutations and never trigger user prompts.
Task Lifecycle
A typical planning loop looks like this:Capture the work
On a new instruction, the agent calls
TaskCreate once per discrete step, providing a short imperative subject and a richer description. New tasks are appended in creation order; their id is a stable, monotonically increasing numeric string ("1", "2", …).Inspect the queue
TaskList returns a compact one-line-per-task summary (id, status, subject, owner, blocked-by), which the agent uses to pick the next available task — typically the lowest-ID pending task with no unresolved blocked_by.Claim and start
Before starting work, the agent calls
TaskUpdate to set the task’s status to in_progress (and optionally an owner for multi-agent scenarios).Get full context
TaskGet returns the full description, dependency edges, and metadata for a specific task — useful right before execution if the description is long.Express Dependencies
Tasks expose two symmetric dependency edges:blocks— the IDs of tasks that cannot start until this one is completed.blocked_by— the IDs of tasks that must complete before this one can start.
TaskUpdate takes add_blocks and add_blocked_by arguments. Each one mutates both sides of the edge automatically, so the data stays consistent:
blocks and blocked_by lists, so the dependency graph remains valid.
TaskList annotates every task that still has unresolved blocked_by entries, and TaskGet returns the full edge list. The agent uses these hints to prefer unblocked work, but enforcement is advisory — nothing in the runtime prevents the model from working on a blocked task. Treat the dependency edges as a coordination signal, not a hard gate.Storage
All task state lives on the agent itself, underagent.state.tasks_context. The relevant types are:
AgentState.tasks_context is a regular field on the agent state model, which means:
- It survives serialization. Calling
agent.state_dict()(or whatever the host platform uses to persistAgentState) captures the task list verbatim, and restoring the state restores the plan. - It is per-agent. Two agents do not share a task list by default; multi-agent coordination is the developer’s job (e.g. by routing all planning tools through one designated planner agent, or by manually syncing state between agents).
- It is mutable from outside the LLM loop. Anything that can reach
agent.state— middleware, application code, evaluators — can read and write tasks directly. The planning tools have no privileged access; they are simply a convenient LLM-facing surface over the same data structure.
Customize Tasks
Because tasks live onagent.state.tasks_context, developers can manage them programmatically without going through the LLM. This is useful for:
- Seeding the agent with a pre-baked plan generated elsewhere (e.g. by another agent, a workflow engine, or static analysis).
- Importing existing work items from an external tracker (Jira, GitHub issues, an internal task DB).
- Migrating state across agent instances or restoring partially completed plans.
- Evaluation of planning behavior, where the harness needs to inject ground-truth tasks before the agent reasons over them.