diff --git a/autogpt_platform/backend/backend/copilot/prompting.py b/autogpt_platform/backend/backend/copilot/prompting.py
index dd630a2e9b..3fdba6fc33 100644
--- a/autogpt_platform/backend/backend/copilot/prompting.py
+++ b/autogpt_platform/backend/backend/copilot/prompting.py
@@ -127,6 +127,17 @@ After building the file, reference it with `@@agptfile:` in other tools:
non-overlapping scope to avoid redundant searches.
+### Agent Building Workflow — ALWAYS follow this
+When the user asks to create an agent, ALWAYS follow this workflow:
+1. Analyze the goal and break it into logical sub-instructions.
+2. Call `decompose_goal` with the steps (each step = one logical task like
+ "add input block", "add AI summarizer", "wire blocks together").
+3. Wait for user approval before proceeding.
+4. After approval, call `create_agent` with the full agent JSON.
+
+For simple goals (1-2 blocks), keep the decomposition brief (2-3 steps).
+For complex goals, decompose into 4-8 steps max.
+
### Tool Discovery Priority
When the user asks to interact with a service or API, follow this order:
diff --git a/autogpt_platform/backend/backend/copilot/tools/__init__.py b/autogpt_platform/backend/backend/copilot/tools/__init__.py
index 6d1a054c32..a15624776f 100644
--- a/autogpt_platform/backend/backend/copilot/tools/__init__.py
+++ b/autogpt_platform/backend/backend/copilot/tools/__init__.py
@@ -17,6 +17,7 @@ from .connect_integration import ConnectIntegrationTool
from .continue_run_block import ContinueRunBlockTool
from .create_agent import CreateAgentTool
from .customize_agent import CustomizeAgentTool
+from .decompose_goal import DecomposeGoalTool
from .edit_agent import EditAgentTool
from .feature_requests import CreateFeatureRequestTool, SearchFeatureRequestsTool
from .find_agent import FindAgentTool
@@ -59,6 +60,7 @@ TOOL_REGISTRY: dict[str, BaseTool] = {
"ask_question": AskQuestionTool(),
"create_agent": CreateAgentTool(),
"customize_agent": CustomizeAgentTool(),
+ "decompose_goal": DecomposeGoalTool(),
"edit_agent": EditAgentTool(),
"find_agent": FindAgentTool(),
"find_block": FindBlockTool(),
diff --git a/autogpt_platform/backend/backend/copilot/tools/decompose_goal.py b/autogpt_platform/backend/backend/copilot/tools/decompose_goal.py
new file mode 100644
index 0000000000..598b0c597b
--- /dev/null
+++ b/autogpt_platform/backend/backend/copilot/tools/decompose_goal.py
@@ -0,0 +1,130 @@
+"""DecomposeGoalTool - Breaks agent-building goals into sub-instructions."""
+
+import logging
+from typing import Any
+
+from backend.copilot.model import ChatSession
+
+from .base import BaseTool
+from .models import (
+ DecompositionStepModel,
+ ErrorResponse,
+ TaskDecompositionResponse,
+ ToolResponseBase,
+)
+
+logger = logging.getLogger(__name__)
+
+MAX_STEPS = 10
+
+
+class DecomposeGoalTool(BaseTool):
+ """Tool for decomposing an agent goal into sub-instructions."""
+
+ @property
+ def name(self) -> str:
+ return "decompose_goal"
+
+ @property
+ def description(self) -> str:
+ return (
+ "Break down an agent-building goal into logical sub-instructions. "
+ "Each step maps to one task (e.g. add a block, wire connections, "
+ "configure settings). ALWAYS call this before create_agent to show "
+ "the user your plan and get approval."
+ )
+
+ @property
+ def parameters(self) -> dict[str, Any]:
+ return {
+ "type": "object",
+ "properties": {
+ "goal": {
+ "type": "string",
+ "description": "The user's agent-building goal.",
+ },
+ "steps": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "description": {
+ "type": "string",
+ "description": "Human-readable step description.",
+ },
+ "action": {
+ "type": "string",
+ "description": (
+ "Action type: 'add_block', 'connect_blocks', "
+ "'configure', 'add_input', 'add_output'."
+ ),
+ },
+ "block_name": {
+ "type": "string",
+ "description": "Block name if adding a block.",
+ },
+ },
+ "required": ["description", "action"],
+ },
+ "description": "List of sub-instructions for the plan.",
+ },
+ "require_approval": {
+ "type": "boolean",
+ "description": "Whether to ask user for approval (default: true).",
+ "default": True,
+ },
+ },
+ "required": ["goal", "steps"],
+ }
+
+ async def _execute(
+ self,
+ user_id: str | None,
+ session: ChatSession,
+ goal: str | None = None,
+ steps: list[dict[str, Any]] | None = None,
+ require_approval: bool = True,
+ **kwargs,
+ ) -> ToolResponseBase:
+ session_id = session.session_id if session else None
+
+ if not goal:
+ return ErrorResponse(
+ message="Please provide a goal to decompose.",
+ error="missing_goal",
+ session_id=session_id,
+ )
+
+ if not steps:
+ return ErrorResponse(
+ message="Please provide at least one step in the plan.",
+ error="missing_steps",
+ session_id=session_id,
+ )
+
+ if len(steps) > MAX_STEPS:
+ return ErrorResponse(
+ message=f"Too many steps ({len(steps)}). Keep the plan to {MAX_STEPS} steps max.",
+ error="too_many_steps",
+ session_id=session_id,
+ )
+
+ decomposition_steps = [
+ DecompositionStepModel(
+ step_id=f"step_{i + 1}",
+ description=step.get("description", ""),
+ action=step.get("action", "add_block"),
+ block_name=step.get("block_name"),
+ status="pending",
+ )
+ for i, step in enumerate(steps)
+ ]
+
+ return TaskDecompositionResponse(
+ message=f"Here's the plan to build your agent ({len(decomposition_steps)} steps):",
+ goal=goal,
+ steps=decomposition_steps,
+ step_count=len(decomposition_steps),
+ requires_approval=require_approval,
+ session_id=session_id,
+ )
diff --git a/autogpt_platform/backend/backend/copilot/tools/models.py b/autogpt_platform/backend/backend/copilot/tools/models.py
index a0d1ad13ef..6c65764469 100644
--- a/autogpt_platform/backend/backend/copilot/tools/models.py
+++ b/autogpt_platform/backend/backend/copilot/tools/models.py
@@ -36,6 +36,9 @@ class ResponseType(str, Enum):
AGENT_BUILDER_VALIDATION_RESULT = "agent_builder_validation_result"
AGENT_BUILDER_FIX_RESULT = "agent_builder_fix_result"
+ # Task decomposition (goal → sub-instructions)
+ TASK_DECOMPOSITION = "task_decomposition"
+
# Block
BLOCK_LIST = "block_list"
BLOCK_DETAILS = "block_details"
@@ -688,3 +691,35 @@ class AgentsMovedToFolderResponse(ToolResponseBase):
agent_names: list[str] = []
folder_id: str | None = None
count: int = 0
+
+
+# Task decomposition models
+
+
+class DecompositionStepModel(BaseModel):
+ """A single step in a decomposed agent-building plan."""
+
+ step_id: str = Field(description="Unique step identifier, e.g. 'step_1'")
+ description: str = Field(description="Human-readable step description")
+ action: str = Field(
+ description="Action type: 'add_block', 'connect_blocks', 'configure', etc."
+ )
+ block_name: str | None = Field(
+ default=None, description="Block being added, if applicable"
+ )
+ status: str = Field(
+ default="pending",
+ description="Step status: pending, in_progress, completed, failed",
+ )
+
+
+class TaskDecompositionResponse(ToolResponseBase):
+ """Response for decompose_goal tool — shows the plan to the user."""
+
+ type: ResponseType = ResponseType.TASK_DECOMPOSITION
+ goal: str = Field(description="The original user goal")
+ steps: list[DecompositionStepModel]
+ step_count: int
+ requires_approval: bool = True
+
+
diff --git a/autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/components/MessagePartRenderer.tsx b/autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/components/MessagePartRenderer.tsx
index 5d129a0a78..0668ea1e24 100644
--- a/autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/components/MessagePartRenderer.tsx
+++ b/autogpt_platform/frontend/src/app/(platform)/copilot/components/ChatMessagesContainer/components/MessagePartRenderer.tsx
@@ -5,6 +5,7 @@ import { ToolUIPart, UIDataTypes, UIMessage, UITools } from "ai";
import { AskQuestionTool } from "../../../tools/AskQuestion/AskQuestion";
import { ConnectIntegrationTool } from "../../../tools/ConnectIntegrationTool/ConnectIntegrationTool";
import { CreateAgentTool } from "../../../tools/CreateAgent/CreateAgent";
+import { DecomposeGoalTool } from "../../../tools/DecomposeGoal/DecomposeGoal";
import { EditAgentTool } from "../../../tools/EditAgent/EditAgent";
import {
CreateFeatureRequestTool,
@@ -144,6 +145,8 @@ export function MessagePartRenderer({
case "tool-run_agent":
case "tool-schedule_agent":
return