Skip to main content

pipecat-piopiy

Piopiy telephony for Pipecat voice agents. Your Pipecat bot takes real phone calls on the Piopiy platform by TeleCMI: calls the Piopiy API places, calls arriving on your numbers, and calls arriving from your PBX over SIP Connect. Mid-call it can transfer the caller to a human, warm or blind, and hang up.

Piopiy bridges each call into a LiveKit room and hands your worker the room. Media runs through Pipecat's own LiveKitTransport; this package supplies the rest - taking the call, knowing who is calling, acting on the call, and hearing about transfers.

Tested with Pipecat v1.8.1. Community-maintained by TeleCMI; not part of the Pipecat core.

Install

pip install pipecat-piopiy
# for the example, with Deepgram + OpenAI + Silero VAD:
pip install "pipecat-piopiy[example]"

Python 3.10+. Depends on pipecat-ai[livekit] and piopiy-agent, the framework-agnostic Piopiy worker SDK.

Use with a pipeline

from pipecat_piopiy import PiopiyRunner, PiopiyCallControl, piopiy_tools
from pipecat_piopiy.processors import PiopiyEventsProcessor

async def bot(transport, call):
    control = PiopiyCallControl(call)
    tools = piopiy_tools(control, transfer_number="919876543210",
                         transfer_caller_id="911203134087")

    context = LLMContext(messages=[{"role": "system", "content": PROMPT}],
                         tools=tools.schemas)
    aggregators = LLMContextAggregatorPair(
        context, user_params=LLMUserAggregatorParams(vad_analyzer=SileroVADAnalyzer()))

    pipeline = Pipeline([
        transport.input(),
        PiopiyEventsProcessor(call),      # transfer progress -> frames + narration
        stt, aggregators.user(), llm, tts,
        transport.output(), aggregators.assistant(),
    ])
    task = PipelineTask(pipeline)

    @transport.event_handler("on_first_participant_joined")
    async def on_caller_joined(_t, participant_id):
        await task.queue_frames([LLMRunFrame()])

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

    await PipelineRunner(handle_sigint=False).run(task)

PiopiyRunner().run(bot)

PiopiyRunner connects to Piopiy as a worker for your agent, and for every call builds a LiveKitTransport pointed at the call's room and calls bot. It accepts the call when the transport connects, which is when the caller is bridged in. Use PipelineRunner(handle_sigint=False): the worker owns the process signals.

Run the example

cd examples/foundational
cp .env.example .env        # agent id, token, API base, transfer number, keys
python 01_piopiy_agent.py

Then call your agent: place a call with POST /v3/voice/ai/call, ring one of your numbers mapped to the agent, or dial the agent id from a PBX registered over SIP Connect. Ask for a person to see a warm transfer, ask for "the billing line" to see a blind transfer, and say goodbye to see it hang up.

Configuration

variable what
PIOPIY_AGENT_ID the agent this worker serves, from the dashboard
PIOPIY_TOKEN the Bearer token, the same one that creates calls
PIOPIY_API_URL the platform's /v3 base URL, as given in your account
PIOPIY_REGISTER optional; host:port of the worker register
PIOPIY_TLS optional; false to talk to the register without TLS (development)
PIOPIY_MAX_SESSIONS calls one process handles at once

What the package gives you

PiopiyCall - who is calling whom: call_id, direction, from_number, to_number, agent_id, variables from the create request, and sip_account_id on SIP Connect calls so one agent can tell your PBXs apart.

PiopiyCallControl - actions on the live call over the Piopiy API:

result  = await control.warm_transfer(to_number="9198...", transfer_summary="Refund on order A-1042")
result  = await control.warm_transfer(sip_uri="sip:desk@pbx.example.com", sip_headers={"X-Ticket": "A-1042"})
result  = await control.blind_transfer(to_number="9198...", caller_id="9112...")
await control.hangup(reason="resolved")
verdict = await control.wait_for_transfer(result.request_id)   # queued -> completed | failed

A warm transfer rings the human while the caller stays in conversation with the agent; on answer the caller is handed over and the agent leaves; if nobody answers the conversation simply continues. A blind transfer hands the caller over at once. One transfer at a time per call: a second one is refused with PiopiyAPIError(409, "transfer_in_progress") carrying the running transfer's request_id.

piopiy_tools() - transfer_call and end_call as LLM function calls. Each FunctionSchema carries its handler, so advertising tools.schemas on the LLMContext is all the wiring. The destination is fixed in code by default; pass allow_model_destination=True to let the model choose a number, and transfer_caller_id for the DID to present, which SIP Connect calls require.

PiopiyEventsProcessor - the platform pushes every transfer's progress into the call's room. The processor turns each message into a PiopiyTransferStatusFrame (started, failed with a reason, completed) and, by default, speaks it: "I'm connecting you now" as the target rings, an apology when it fails, plus a note into the LLM context so the model carries on sensibly. Pass narrate=False to handle the frames yourself. completed is best-effort: at that moment the agent is being removed from the call, and on_participant_left fires.

Notes

  • Every action uses the call's customer leg, which PiopiyCall.call_id is.
  • SIP Connect calls consume no phone number, so a transfer to a phone from one needs transfer_caller_id (a DID you own).
  • Accept timing is handled for you: the runner accepts on on_connected, and if the join missed the platform's deadline it cancels the bot so two agents never share a call.
  • Pipecat changes quickly. This release is tested against v1.8.1; the pinned range in pyproject.toml is >=1.8,<2.

License

MIT. Copyright TeleCMI.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pipecat_piopiy-0.1.0.tar.gz (21.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pipecat_piopiy-0.1.0-py3-none-any.whl (19.4 kB view details)

Uploaded Python 3

File details

Details for the file pipecat_piopiy-0.1.0.tar.gz.

File metadata

  • Download URL: pipecat_piopiy-0.1.0.tar.gz
  • Upload date:
  • Size: 21.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.4

File hashes

Hashes for pipecat_piopiy-0.1.0.tar.gz
Algorithm Hash digest
SHA256 fc6b2ea4fde455b2f3a2eb0162b04ead3c6ce92f71c03786114a82ab3deec4ba
MD5 45fc0e2ff8020dad630be8e1560dbb72
BLAKE2b-256 0d5c9c5caac2df196adcc70894d8dd49d9c567ebdf9bf1626bbda3ba22f6b2be

See more details on using hashes here.

File details

Details for the file pipecat_piopiy-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: pipecat_piopiy-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 19.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.4

File hashes

Hashes for pipecat_piopiy-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 d3a5c9b33c632ff18cd0a5f4e0e69e7801e54666ba87c6b1e4d07fcff571c0ec
MD5 20489708bbff704c9ce28110b13848de
BLAKE2b-256 8f2cfd219da736a3ecec15099b6d4ea0119707cd71c55ec7b02168064b899d88

See more details on using hashes here.

Release history Release notifications | RSS feed

0.2.4

2 files

0.2.2

2 files

0.2.1

2 files

0.2.0

2 files

This release

0.1.0 This release

2 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