Skip to main content

par-ai

Protocol-first orchestration for AI agents.
Declarative multiparty session types for AI agents

What it is

You describe one typed global choreography between named roles. par-ai projects it onto every role, rejects alts a role cannot observe, and runs the session. A language model fills a typed payload or picks a declared branch — it does not route the workflow, invent roles, or call arbitrary code. The protocol owns control; the model owns content.

What it catches

A role that must behave differently on two branches of a alt it never saw fails before any model call:

>>> from par_ai.kernel.errors import ProjectionError
>>> from par_ai import Nothing, Text
>>> from par_ai.protocol import alt, msg, project
>>> from par_ai.kernel.role import roles
>>> A, B, C = roles("A", "B", "C")
>>> broken = alt[A, B] (
...     Nothing("Yes") >> msg[A, C] ("Y", Text),
...     Nothing("No") >> msg[C, A] ("N", Text),
... ).close()
>>> try:
...     project(broken, C)
... except ProjectionError as err:
...     print("role" in str(err).lower() and "Yes" in str(err))
True

Install

pip install par-ai
pip install "par-ai[openai]"   # optional OpenAI Responses backend

Quickstart

Minimal agent session with the OpenAI gpt-5.6-luna model:

import asyncio

from openai import AsyncOpenAI

from par_ai.agent import Agent
from par_ai.human import Human, ScriptedHumanIo
from par_ai import OpenAIModel
from par_ai import Text
from par_ai.protocol import msg, render
from par_ai.kernel.role import roles
from par_ai.runtime import AgentRuntime

A, B = roles('Writer', 'Reader')
proto = msg[A, B]('Note', Text).close()
print(render(proto))
model = OpenAIModel('gpt-5.6-luna', AsyncOpenAI(max_retries=0, timeout=30.0))
writer = Agent(model, A, 'send a short note', proto)
reader = Human(B, proto, ScriptedHumanIo([]))


async def main() -> None:
    trace = await AgentRuntime(proto, [writer, reader]).run()
    print(trace[0].payload)


asyncio.run(main())

Examples — live in 10 seconds

export OPENAI_API_KEY=...
pip install 'par-ai[openai]'
uv run python examples/online/hello.py

Sample output:

=== protocol ===
Writer -> Reviewer : Note(str)
Reviewer -> Writer : Ack(str)
end
=== conversation ===
Writer:Note -> Reviewer 'Ship the typed choreography first.'
Reviewer:Ack -> Writer 'Received.'

Catch a projection error without a key: uv run python examples/offline/projection_error.py. Full ladder: examples/README.md.

When to use — and when not to

Use when

  • the allowed interaction shape is known up front
  • every role must only act on messages it actually receives
  • you need projection to fail closed before the first model call
  • tools are roles with a protocol surface, not free function-calling
  • sessions must resume from recorded decisions without re-asking

Do not use when

  • one agent with a free tool set is enough (use a simpler agent SDK)
  • the route must be discovered at runtime by the model
  • you need a large catalogue of vendor integrations out of the box
  • you require a stable API before 1.0 (this project is research / 0.x)
  • you need multi-process or multi-machine transport (runtime is in-process)

Links

Status

Research framework at 0.1.x. What par-ai proves, checks at run time, and deliberately leaves to the application — including the non-guarantees (no deadlock-freedom, no liveness, no exactly-once) — is the guarantee table. Public surface is the union of tier-1/2 __all__ exports; see tests/public_api.txt. Exception types are stable; message text and journal formats are not.

Security

Untrusted payloads and web content are data, not instructions. User-written tools run with the host process privileges — sandbox them and validate paths or commands before any effect. Give AsyncOpenAI a finite transport timeout (the model wrapper does not add one). Deadline, Allowance, and Metered bound branch windows, protocol steps, and token spend. Journals and tracers persist payloads and model output in plaintext.

Private reports: SECURITY.md. Guidance: security.

Development

uv sync --all-groups
just all    # or: uv run nox -t ci

Agent conventions for contributors live in AGENTS.md.

License

MIT — see LICENSE.

Download files

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

Source Distribution

agentsparty-0.1.0.tar.gz (110.1 kB view details)

Uploaded Source

Built Distribution

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

agentsparty-0.1.0-py3-none-any.whl (141.2 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: agentsparty-0.1.0.tar.gz
  • Upload date:
  • Size: 110.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.9 {"installer":{"name":"uv","version":"0.10.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"NixOS","version":"25.11","id":"xantusia","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for agentsparty-0.1.0.tar.gz
Algorithm Hash digest
SHA256 cbaf3cef315f5f494ef0427c5f2009ec1369590eec69e6597deb48049047824d
MD5 7169ca082b4dce118fc31cf697ddbe45
BLAKE2b-256 67ded3a8fd5c796e18a7337f1c5f2ea7c4b512a7ce8ed6b01053f0b0fceb8736

See more details on using hashes here.

File details

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

File metadata

  • Download URL: agentsparty-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 141.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.9 {"installer":{"name":"uv","version":"0.10.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"NixOS","version":"25.11","id":"xantusia","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for agentsparty-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 7691ad03ecac638bc85f694e28b45180a09dc8d9b8e19aa8ec7833f9e9cb387c
MD5 dd7db09f61d1bcb0f8b846f4c02cd618
BLAKE2b-256 ae719aebb068bc6b372320bb9c019c100299d3337d34e7791dd3ef08f574a301

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 Sentry Error logging StatusPage Status page