Documentation Index
Fetch the complete documentation index at: https://docs.pipecat.ai/llms.txt
Use this file to discover all available pages before exploring further.
What are tasks?
Tasks let one agent dispatch work to other agents. While handoff transfers the conversation, tasks are for background work — an agent asks workers to do something and collects their results. Use cases for tasks:- Researching a topic from multiple perspectives in parallel
- Running a code analysis while talking to the user
- Fetching data from multiple sources simultaneously
Single task
The simplest form isself.task(), which sends a task to one agent and waits for the response:
self.task() is a context manager that handles the full lifecycle: it waits for the agent to be ready, sends the request, and collects the response. Under the hood, this is equivalent to calling request_task() (fire-and-forget) and then handling on_task_response() and on_task_completed() yourself.
Task group
When you need to dispatch work to multiple agents in parallel, useself.task_group():
self.task_group() works the same way but for multiple agents: it waits for all of them to be ready, sends a request to each, and collects all responses. Under the hood, this is equivalent to calling request_task_group() and then handling on_task_response() for each agent and a final on_task_completed() yourself.
The same payload is sent to every agent. If you need different arguments per agent, you can structure the payload so each worker reads its own key:
Handling task requests
Workers handle incoming tasks in two ways.The @task decorator
The@task decorator marks a method as a task handler. The framework automatically dispatches matching requests to it. The decorator requires a name argument. The worker passes message.task_id when sending the response:
Overriding on_task_request
Alternatively, you can overrideon_task_request() directly without the @task decorator:
send_task_response(), send_task_update(), and send_task_stream_*() all require an explicit task_id. This lets a worker handle multiple concurrent tasks and respond to each one correctly. For simple handlers, pass message.task_id from the request. For asynchronous responses (see the example below), track the task_id yourself until you’re ready to respond.Building a task system
Let’s build a debate system where a moderator dispatches a topic to three workers, each arguing from a different perspective.Worker agents
Each worker runs its own LLM pipeline. The LLM response arrives asynchronously through an event handler, so the worker tracks the current task ID until it has something to respond with:LLMContextAgent extends LLMAgent with a built-in LLMContext and aggregator pair. It automatically builds the pipeline as [user_aggregator, llm, assistant_aggregator], so you don’t need to wire the context plumbing yourself. Access the aggregators via self.user_aggregator and self.assistant_aggregator in on_ready() or later hooks.- Receives a task request and stores the
task_id - Injects the topic into its LLM context and runs the LLM
- When the LLM finishes its turn, the event handler sends the response with the stored
task_id
Coordinator agent
The coordinator creates workers, triggers tasks via a tool, and synthesizes results:- The LLM calls the
debatetool task_group()sends the topic to all three workers in parallel- Each worker runs its own LLM and responds with its perspective
- The moderator collects all responses and returns them to the LLM
- The LLM synthesizes a balanced summary and speaks it to the user
Task lifecycle
Request
Parent calls
task() or task_group(). The framework waits for workers to be ready, then sends a task request to each.Task cancellation
Tasks can be cancelled in several ways. The framework handles cleanup automatically and notifies workers so they can stop in-progress work.Automatic cancellation with context managers
When usingtask() or task_group(), cancellation happens automatically if the context block raises an exception. This includes tool interruptions (CancelledError) when using cancel_on_interruption=True:
Worker errors
By default (cancel_on_error=True), if any worker responds with an error status, the remaining workers in the group are cancelled and TaskGroupError is raised:
Manual cancellation with cancel_task()
For fire-and-forget tasks (usingrequest_task()), you manage cancellation yourself by tracking task IDs:
Handling cancellation on the worker side
When a task is cancelled, the worker’son_task_cancelled hook fires. The framework automatically sends a CANCELLED response back to the requester, so you only need to override this hook if you have resources to clean up:
Agent shutdown
When a worker agent stops with tasks still in flight, it automatically sends aCANCELLED response for each active task so requesters aren’t left waiting on a timeout.
What’s next
You now understand the core concepts of Pipecat Subagents: agents, the bus, handoff, and tasks. The Fundamentals section covers specific patterns in depth.What's Next
Explore Fundamentals and advanced patterns