AG2 Assistant

Agents Architecture

The LLM agents in AG2 Assistant — who they are, their tools, their prompts, and where the design is currently disconnected. A working note for review (June 2026).

Superseded (July 2026). The task subsystem described below (chat agent → planner → executor(s) → verifier → controller, with plans, subtasks, deliverables, and an intake step) was replaced by the Cowork-style tasks redesign: a Task is just standing config (name + prompt + optional model + schedule), and each Run is a single ordinary turn of the one universal agent on its own chat stream (task-run:<run_id>) — no planner, no subtask tree, no verifier, no separate controller agent. See architecture.md (§5.5 "Task subsystem" and §6 "Agents & LLM calls") for the current design; this page is kept as the historical note that motivated the redesign.

AG2 Assistant runs five distinct LLM agents (plus two non-conversational passes), each created in a different module with its own model, tools, and prompt. Work flows between them as a relay — and because each is a fresh agent with a partial view, capabilities like scheduling are known to some and invisible to others. That fragmentation is the source of the rough edges.

chat agent ──(start_task / schedule_task)──▶ TASK │ prepare_task │ intake + plan ▼ planner ──▶ TaskPlan (objective, deliverables, subtasks) │ runner │ executes the plan ▼ executor(s) ──▶ deliverable ──▶ verifier (accept / reject) │ task chat (edit) ──▶ controller ──(add/cancel/reschedule)──▶ TASK

player flow: the chat agent spawns a task; a planner turns the request into a plan; the runner drives executor agents per subtask; a verifier gates each deliverable; the controller edits the task from its chat.

The five agents

#AgentCreated inModelToolsPrompt (per turn)
1 Chat agent
the conversational assistant
agent.create_agent (gateway / channels) main web search, web_fetch, read_file 🔒, shell 🔒, code 🔒, skills, Google (when signed in) + start_task + schedule_task turn_prompt: persona + BEHAVIOR_GUIDANCE + GOOGLE_GUIDANCE (if signed in) + live env
2 Planner
request → plan
TaskService._planner_agentcreate_agent(memory=False, skills=False) main full tool set minus start_task / schedule_task / skills — but unused (a single structured call) base = persona only; message = _PLAN_PROMPT → returns a TaskPlan
3 Executor
one per (sub)task
executor.make_task_executorcreate_agent(capabilities=…, model=sub_model) cheap leaf subtasks
main root / synthesis
capability-scoped subset only (e.g. just web) turn_prompt (persona + behaviour + env) + message: "produce the deliverable… original request… objective… deliverables now"
4 Deliverable-verifier
ephemeral, per deliverable
executor._verify_deliverableAgent("deliverable-verifier") cheap none no persona / no behaviour — "judge output vs criteria (+ grounding)" → _Verdict
5 Task-controller
the per-task chat
TaskService._controlAgent("task-controller", tools=build_task_tools) main task_status, add_subtask, set_objective, add_deliverable, reschedule, cancel [_CONTROL_PROMPT, live task snapshot]no persona / behaviour / env

🔒 = permission-gated. Plus two non-agents: a memory-aggregation summarization pass (cheap model) and onboarding (scripted Q&A via the Asker, no LLM).

Prompt summaries

BEHAVIOR_GUIDANCE — shared by agents 1 & 3 only

Do what's asked with the right tool; don't shell-flail or improvise; you can't watch video/audio; ask the user when you genuinely need info or confirmation.

_PLAN_PROMPT — agent 2 (planner)

Classify trivial vs non-trivial; ask 2–5 clarifying questions about scope, audience, format, depth, deadline; emit objective + deliverables + subtasks + per-piece capabilities. Final deliverable belongs to the root and is synthesised from subtasks.

executor message — agent 3

Produce the actual deliverable content with your tools; here's the original request, objective, parent context, completed-subtask results, and the deliverables to produce now; involve the user if you need to.

verifier — agent 4

Strict check: is the finished deliverable content present and meeting the criteria? For web research, is it grounded in the retrieved sources? (Asking clarifying questions mid-turn is fine; punting is not.)

_CONTROL_PROMPT — agent 5 (controller)

You steer ONE task. Use your tools to add/cancel subtasks, change the objective, reschedule, or cancel — immediately, then confirm. Use reschedule for timing changes, never a subtask. You do NOT do the work yourself — the runner does.

Why it feels disconnected

1. Scheduling isn't a shared primitive — it's tools bolted onto one agent. Only the chat agent knows scheduling (schedule_task). The planner has no concept of it, and _PLAN_PROMPT literally invites "deadline" questions — so when a scheduled task runs intake, the planner asks the user how/when to schedule, re-litigating something already decided. The controller has reschedule but via yet another prompt. No agent treats "this task has a schedule" as known metadata.
2. Shared prompt fragments are applied inconsistently. Persona + behaviour + env reach the chat & executor agents (via turn_prompt); the planner gets persona-only; the controller and verifier get neither. Tone and rules drift between stages.
3. The pipeline is a relay of partial views. chat → planner → executor → verifier → controller, each a fresh LLM that re-derives context from a hand-built message. None sees the task's full metadata (schedule, origin, capabilities, intake answers) in a uniform way — the planner never receives the schedule, the controller gets a text snapshot, the executor gets a different hand-assembled blob.
4. The planner is a heavyweight agent used for a single structured call and carries unused web/shell/Google tools. Conceptually it's just "request → TaskPlan."

The shape of a fix

Direction only — nothing built yet.