Skip to main content

relaymessenger-pipecat

Answer a Relay Call with a Pipecat bot. RelayTransport joins the Call as the agent: the caller's voice and camera come into your pipeline, and your bot's audio and video go back into the Call.

pip install relaymessenger-pipecat

Python 3.11 or newer, with pipecat-ai 1.11 or newer. The media core is relaymessenger.calls from the Relay SDK (relaymessenger[calls]); it uses only Relay's public API with the agent's token, so your code never handles SDP, ICE, or SFU credentials.

Answer a Call

Your agent receives call.created through a Relay webhook or the Agent WebSocket. Build the transport from that Call's ID and run a pipeline, the same way you would with Pipecat's LiveKit transport:

import os

from pipecat.frames.frames import LLMRunFrame
from pipecat.pipeline.pipeline import Pipeline
from pipecat.pipeline.worker import PipelineWorker
from pipecat.workers.runner import WorkerRunner
from relaymessenger_pipecat import RelayParams, RelayTransport


async def answer(call_id: str) -> None:
    transport = RelayTransport(
        api_key=os.environ["RELAY_AGENT_TOKEN"],
        call_id=call_id,
        params=RelayParams(audio_in_enabled=True, audio_out_enabled=True),
    )
    # stt, llm and tts are your Pipecat services; the aggregators hold the LLM context.
    worker = PipelineWorker(
        Pipeline([transport.input(), stt, user_aggregator, llm, tts, transport.output(), assistant_aggregator]),
        cancel_on_idle_timeout=False,  # a quiet call is still a call
    )

    @transport.event_handler("on_first_participant_joined")
    async def on_first_participant_joined(transport, participant_id):
        await worker.queue_frames([LLMRunFrame()])  # the model speaks first, in its own words

    @transport.event_handler("on_participant_left")
    async def on_participant_left(transport, participant_id, reason):
        await worker.cancel()

    runner = WorkerRunner()
    await runner.add_workers(worker)
    await runner.run()

Joining answers a ringing Call, so start the pipeline within the Call's 32-second ring. The pipeline starts once the agent has joined the Call's room, while its media is still connecting, so the bot can start its greeting on on_call_state_updated with in-progress; on_connected fires when media connects. The bot's audio is held until the caller is receiving it, so a greeting is heard from its first word. on_first_participant_joined fires once the caller's audio reaches the agent. transport.end() ends the Call for both sides.

Text the person during a Call

relay_chat_tools gives the bot's LLM tools for the Call's chat, through Pipecat's function calling: send_message, send_buttons, send_selection, send_place, request_location, read_location and send_link. Each tool sends with the Relay SDK and its part helpers, as the agent. A failed send goes back to the model as {"status": "failed", "error": ...}, so the bot can say so. load_chat_context reads the chat's recent messages as LLM context messages, so the bot knows the chat before it speaks.

import os

from pipecat.processors.aggregators.llm_context import LLMContext
from relaymessenger import Relay
from relaymessenger_pipecat import load_chat_context, relay_chat_tools

relay = Relay(api_key=os.environ["RELAY_AGENT_TOKEN"])
call = await relay.calls.retrieve(call_id)
chat_id = call["call"]["chat_id"]

chat_tools = relay_chat_tools(relay, chat_id)
chat_tools.register(llm)  # llm is your Pipecat LLM service
context = LLMContext(
    messages=[{"role": "system", "content": "..."}, *await load_chat_context(relay, chat_id)],
    tools=chat_tools.tools,
)

Send and receive video

Set video_in_enabled=True to receive the caller's camera as UserImageRawFrames in RGB. Set video_out_enabled=True to send OutputImageRawFrames in RGB, RGBA, BGRA or ARGB, sized by video_out_width and video_out_height. The camera track is published with the audio when the bot joins, and sends one black frame a second until the bot's first image.

examples/echo_bot.py is a complete bot. It waits for the next Call on the Agent WebSocket, echoes the caller's voice back, and sends a moving test pattern:

RELAY_AGENT_TOKEN=... uv run examples/echo_bot.py

A talking avatar

examples/simli_avatar_bot.py is Pipecat's own Simli example on a Relay Call: Deepgram, OpenAI and Cartesia make the voice, and Pipecat's SimliVideoService turns it into the frames of a talking face, which RelayTransport sends as the agent's camera.

uv run --with 'pipecat-ai[simli,deepgram,cartesia,openai,silero]' examples/simli_avatar_bot.py

Drive a Rive file

Instead of sending video, the agent can have the phone draw its own Rive file (the rive on its profile) and drive it live. Put RelayRiveProcessor right after the TTS service: TTS word timestamps become a viseme number (Preston Blair's ten mouths, 0 rest to 9 WQ) and the bot speaking frames a speaking boolean on the file's View Model, each timed against the agent's audio so the mouth moves when the words are heard.

from relaymessenger_pipecat import RelayRiveProcessor

pipeline = Pipeline([transport.input(), stt, user_aggregator, llm, tts, RelayRiveProcessor(transport), transport.output(), assistant_aggregator])

Rename the properties with viseme_property= and speaking_property=, or pass None to leave one alone. For anything else (a score, a mood, another file), use the channel directly: rive = await transport.call.rive(), then rive.set(...), rive.trigger(...), rive.show(...), and rive.on("view_model" | "trigger", ...) for what the person does in the file. examples/rive_bot.py is the Simli example with the processor in place of the video service.

Use your own TURN servers

Pass ice_servers a list of RTCIceServer dicts, or an async function that returns one per media attempt, so short-lived credentials are minted each time. The example shows Cloudflare TURN.

Metadata

Release files for relaymessenger-pipecat 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for relaymessenger-pipecat 0.1.1
File Size Uploaded
relaymessenger_pipecat-0.1.1.tar.gz 231.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for relaymessenger-pipecat 0.1.1
File Interpreter ABI Platform
relaymessenger_pipecat-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 250.3 kB

Release files / relaymessenger_pipecat-0.1.1.tar.gz

Download URL relaymessenger_pipecat-0.1.1.tar.gz
Size 231.5 kB
Tags Source
SHA-256 checksum
How to use checksums
dadaae4535de5daf17af3badc4380ede1556f5a2cc6ce45afbd62b6fda1d2d5c
BLAKE2b-256 checksum
How to use checksums
3d3dd08dd6099a66d1c5c71fdfcee0e7d6104ac816b581eafa8a4aea4f8006f3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / relaymessenger_pipecat-0.1.1-py3-none-any.whl

Download URL relaymessenger_pipecat-0.1.1-py3-none-any.whl
Size 18.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
86ee383a39dd87f41793091b2a3f4c0462fd091e66e41171bb836f4fcd89a459
BLAKE2b-256 checksum
How to use checksums
c9e20fe7d5ad7aed2c65e140e17394d68ffd2de5f1b2679e4328633f468e7b9e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page