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 jobs?
Jobs let one agent dispatch work to other agents. While handoff transfers the conversation, jobs are for background work — an agent asks other agents to do something and collects their results. Use cases for jobs:- Researching a topic from multiple perspectives in parallel
- Running a code analysis while talking to the user
- Fetching data from multiple sources simultaneously
Single job
The simplest form isself.job(), which sends a job to one agent and waits for the response:
self.job() 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_job() (fire-and-forget) and then handling on_job_response() and on_job_completed() yourself.
Job group
When you need to dispatch work to multiple agents in parallel, useself.job_group():
self.job_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_job_group() and then handling on_job_response() for each agent and a final on_job_completed() yourself.
The same payload is sent to every agent. If you need different arguments per agent, you can structure the payload so each one reads its own key:
Handling job requests
Agents handle incoming jobs in two ways.The @job decorator
The@job decorator marks a method as a job handler. The framework automatically dispatches matching requests to it. The decorator requires a name argument. The handler responds with message.job_id:
Overriding on_job_request
Alternatively, you can overrideon_job_request() directly without the @job decorator:
send_job_response(), send_job_update(), and send_job_stream_*() all
require an explicit job_id. This lets an agent handle multiple concurrent
jobs and respond to each one correctly. For simple handlers, pass
message.job_id from the request. For asynchronous responses (see the example
below), track the job_id yourself until you’re ready to respond.Building a job system
Let’s build a debate system where a moderator dispatches a topic to three agents, each arguing from a different perspective.Worker agents
Each debate agent runs its own LLM pipeline. The LLM response arrives asynchronously through an event handler, so the agent tracks the current job ID until it has something to respond with:LLMContextWorker extends LLMWorker with a built-in LLMContext and
aggregator pair. It builds the pipeline as [user_aggregator, llm, assistant_aggregator] automatically, so you don’t need to wire the context
plumbing yourself. Access the aggregators via self.user_aggregator and
self.assistant_aggregator.- Receives a job request and stores the
job_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
job_id
Coordinator agent
The moderator triggers jobs via a tool and synthesizes the results:runner.add_workers(ModeratorAgent("moderator", llm=...), DebateWorker("advocate"), DebateWorker("critic"), DebateWorker("analyst")).
When the user says “debate whether AI should be regulated,” the moderator:
- The LLM calls the
debatetool job_group()sends the topic to all three agents in parallel- Each agent 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
Job lifecycle
Request
The requester calls
job() or job_group(). The framework waits for agents
to be ready, then sends a job request to each.Job cancellation
Jobs can be cancelled in several ways. The framework handles cleanup automatically and notifies agents so they can stop in-progress work.Automatic cancellation with context managers
When usingjob() or job_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 agent responds with an error status, the remaining agents in the group are cancelled and JobGroupError is raised:
Manual cancellation
For fire-and-forget jobs (usingrequest_job()), you manage cancellation yourself by tracking job IDs:
Handling cancellation on the agent side
When a job is cancelled, the agent’son_job_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 an agent stops with jobs still in flight, it automatically sends aCANCELLED response for each active job so requesters aren’t left waiting on a timeout.
What’s next
You now understand the core concepts of Pipecat’s multi-agent system: agents, the bus, handoff, and jobs. The Fundamentals section covers specific patterns in depth.Voice-enabling a client UI
A concrete application of jobs: a UIWorker that sees and drives the user’s GUI
over a two-way RTVI interface.
What's Next
Explore Fundamentals and advanced patterns