Skip to main content

Python SDK for Pacerelle encrypted local agent relays.

Project description

Pacerelle Python SDK

Python agent client for Pacerelle encrypted local agent relays.

Use this SDK to connect a local Python process to Pacerelle, receive messages, reply to conversations, drive widgets, and return encrypted files or media.

pip install --pre pacerelle

Alpha release: APIs may change before the first stable release. Production wheels bundle the native Signal runtime for the target platform.

Requirements

  • Python 3.12 for the current alpha wheels.
  • A supported platform wheel: Windows x64, Linux x64, Linux ARM64, or macOS ARM64.

Python 3.11 support is planned, but the current alpha release is tested and published for CPython 3.12 only.

Before You Run

Create an agent in Pacerelle. The confirmation panel shows both Identifiant de l'agent and Jeton d'authentification. Use Copier la configuration .env to copy the required variables.

export PACERELLE_AGENT_ID="agent-id"
export PACERELLE_AGENT_TOKEN="agent-token"

On Windows PowerShell:

$env:PACERELLE_AGENT_ID = "agent-id"
$env:PACERELLE_AGENT_TOKEN = "agent-token"

Published packages connect to the Pacerelle API by default. Local source builds default to http://localhost:8080 for development.

Agent Connect

Third-party Python applications can install an agent only after the user approves the request in Pacerelle. Keep the PKCE verifier, state, installation token, and runtime token on the application server.

from pacerelle import (
    begin_agent_connect,
    exchange_agent_connect_code,
    request_agent_runtime_token,
)

pending = begin_agent_connect(
    connect_key=user_supplied_connect_key,
    client_id=pacerelle_client_id,
    redirect_uri="https://your-app.example/pacerelle/callback",
    agent_name="Research assistant",
)
# Redirect the user to pending.authorization_url and verify pending.state.

installation = exchange_agent_connect_code(
    code=callback_code,
    code_verifier=pending.code_verifier,
    client_id=pacerelle_client_id,
    redirect_uri="https://your-app.example/pacerelle/callback",
)
runtime = request_agent_runtime_token(
    installation_token=installation.installation_token,
)

Minimal Echo Agent

import asyncio
import os

from pacerelle import AgentGatewayClient

client = AgentGatewayClient(
    token=os.environ["PACERELLE_AGENT_TOKEN"],
    agent_id=os.environ["PACERELLE_AGENT_ID"],
    e2ee=True,
)


async def handle(message, agent):
    await agent.send_message(
        conversation_id=message.conversation_id,
        to=message.from_id,
        reply_to_message_id=message.id,
        text=f"Received: {message.text}",
    )


client.on_message(handle)
asyncio.run(client.connect())

Incoming Messages

The handler receives an AgentMessage:

async def handle(message, agent):
    print(message.id)
    print(message.conversation_id)
    print(message.from_id)
    print(message.text)
    print(message.attachments)
    print(message.widget_response)

Use message.from_id as the to value when replying to the user.

Sending Messages And Replies

Send a normal message:

await agent.send_message(
    conversation_id=message.conversation_id,
    to=message.from_id,
    text="I can help with that.",
)

Reply to a specific user message:

await agent.send_message(
    conversation_id=message.conversation_id,
    to=message.from_id,
    reply_to_message_id=message.id,
    text="Replying to your last message.",
)

Running Your Own Agent Logic

async def handle(message, agent):
    result = await run_my_agent(message.text)

    await agent.send_message(
        conversation_id=message.conversation_id,
        to=message.from_id,
        reply_to_message_id=message.id,
        text=result,
    )

Widgets

Widgets are sent as encrypted conversation messages. Each method returns the widget id. User answers arrive later as message.widget_response.

Confirm

await agent.send_confirm_widget(
    conversation_id=message.conversation_id,
    to=message.from_id,
    widget_id="confirm-delete",
    title="Delete file?",
    body="This cannot be undone.",
    danger=True,
    labels={"yes": "Delete", "no": "Cancel"},
)

Handle the answer:

if message.widget_response and message.widget_response.ref == "confirm-delete":
    if message.widget_response.cancelled:
        return
    if message.widget_response.value is True:
        await agent.send_message(
            conversation_id=message.conversation_id,
            to=message.from_id,
            text="Confirmed.",
        )

Choice

await agent.send_choice_widget(
    conversation_id=message.conversation_id,
    to=message.from_id,
    widget_id="choose-format",
    title="Choose a format",
    options=[
        {"id": "pdf", "label": "PDF"},
        {"id": "csv", "label": "CSV"},
    ],
    multi=False,
)

Permission

await agent.send_permission_widget(
    conversation_id=message.conversation_id,
    to=message.from_id,
    widget_id="permission-files",
    title="Allow file access?",
    body="The agent needs access to selected files.",
    scopes=["once", "session"],
)

Form

await agent.send_form_widget(
    conversation_id=message.conversation_id,
    to=message.from_id,
    widget_id="profile-form",
    title="Complete profile",
    submitLabel="Save",
    fields=[
        {"name": "email", "label": "Email", "type": "email", "required": True},
        {"name": "notes", "label": "Notes", "type": "textarea"},
    ],
)

Progress

progress_id = await agent.send_progress_widget(
    conversation_id=message.conversation_id,
    to=message.from_id,
    widget_id="import-progress",
    title="Importing files",
    value=10,
    max=100,
    cancellable=True,
)

Update it:

await agent.send_widget_update(
    conversation_id=message.conversation_id,
    to=message.from_id,
    ref=progress_id,
    spec={"value": 65, "body": "Almost done"},
)

File Picker

await agent.send_file_picker_widget(
    conversation_id=message.conversation_id,
    to=message.from_id,
    widget_id="pick-files",
    title="Choose files",
    multiple=True,
    accept=[".pdf", "image/*"],
    max_files=5,
)

Date And Time

await agent.send_datetime_widget(
    conversation_id=message.conversation_id,
    to=message.from_id,
    widget_id="schedule",
    title="Pick a meeting time",
    mode="datetime",
    min="2026-05-21T09:00:00",
)

Files And Media

send_file and send_media encrypt bytes locally with AES-GCM, upload only ciphertext to /agent/blobs, then send the attachment key and IV inside the E2EE message payload.

await agent.send_file(
    conversation_id=message.conversation_id,
    to=message.from_id,
    reply_to_message_id=message.id,
    text="Here is the report.",
    name="report.txt",
    mime="text/plain",
    data=b"private report",
)

Media adds optional dimensions or duration:

await agent.send_media(
    conversation_id=message.conversation_id,
    to=message.from_id,
    text="Preview attached.",
    name="chart.png",
    mime="image/png",
    data=png_bytes,
    width=1200,
    height=800,
)

Encryption

When e2ee=True, the SDK encrypts and decrypts messages locally before they leave your machine. On connect, the client publishes the agent pre-key bundle, establishes encrypted sessions for conversations, and keeps message contents opaque to the relay.

Use e2ee=False only for local debugging or non-encrypted transports.

MCP

This package is the Python SDK for building agents. The MCP server is distributed separately:

npx -y @pacerelle/mcp-server

Project details


Download files

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

Source Distribution

pacerelle-0.1.0a4.tar.gz (105.0 kB view details)

Uploaded Source

Built Distributions

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

pacerelle-0.1.0a4-cp312-cp312-win_amd64.whl (774.3 kB view details)

Uploaded CPython 3.12Windows x86-64

pacerelle-0.1.0a4-cp312-cp312-manylinux_2_34_x86_64.whl (912.7 kB view details)

Uploaded CPython 3.12manylinux: glibc 2.34+ x86-64

pacerelle-0.1.0a4-cp312-cp312-macosx_14_0_arm64.whl (619.8 kB view details)

Uploaded CPython 3.12macOS 14.0+ ARM64

File details

Details for the file pacerelle-0.1.0a4.tar.gz.

File metadata

  • Download URL: pacerelle-0.1.0a4.tar.gz
  • Upload date:
  • Size: 105.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for pacerelle-0.1.0a4.tar.gz
Algorithm Hash digest
SHA256 4e857a938064863fe64253e7ee4704429d4c3caabfd61a32bc7061d17a473e8b
MD5 5231a93e1e43752b8173a18591712f13
BLAKE2b-256 36eb468e4fae9001785d7b7d4c46d82bc72c8358d14110bf7dbff08ed685a7ae

See more details on using hashes here.

File details

Details for the file pacerelle-0.1.0a4-cp312-cp312-win_amd64.whl.

File metadata

File hashes

Hashes for pacerelle-0.1.0a4-cp312-cp312-win_amd64.whl
Algorithm Hash digest
SHA256 5bac1df9a225754867f7199a64cc31648be038186d93883d911f10f936028711
MD5 198e4603ae28da425cdbe4920f542359
BLAKE2b-256 9baafc0cebcd24a3ec8ea029eaee3113f6fe018e5cd405edb73c47d5e741fd04

See more details on using hashes here.

File details

Details for the file pacerelle-0.1.0a4-cp312-cp312-manylinux_2_34_x86_64.whl.

File metadata

File hashes

Hashes for pacerelle-0.1.0a4-cp312-cp312-manylinux_2_34_x86_64.whl
Algorithm Hash digest
SHA256 e5648b5fc83f2ff3d4ae50fb4afc40be5789a01e989a9d0c2d5f427fcf94136b
MD5 e6c78cb315e59be5e18b53e25b0d113b
BLAKE2b-256 161a635fbc92d301bd69be1bee44edc87e8e3ebd3f7b2e19a09bd8286a8743de

See more details on using hashes here.

File details

Details for the file pacerelle-0.1.0a4-cp312-cp312-macosx_14_0_arm64.whl.

File metadata

File hashes

Hashes for pacerelle-0.1.0a4-cp312-cp312-macosx_14_0_arm64.whl
Algorithm Hash digest
SHA256 603edd31d7e18db2d7b9b9f43c65c63921cfd2fd5e46fecbcadec1b8d412d174
MD5 59e12e22416c3021675f8671bb913fab
BLAKE2b-256 064fd2d7608b67850fee70dbed723e9ab26746987891a197b692f9f1d7de4a8f

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page