Skip to main content

pi-py

Python port of pi's core libraries, published on PyPI as one package, pi-ai-python, with these import packages:

Import Upstream What it does
pi_ai @earendil-works/pi-ai Unified LLM API: provider collections, auth resolution (API keys, OAuth), streaming events, token and cost tracking, tool calling, cross-provider context hand-off, image generation, classification
pi_agent @earendil-works/pi-agent-core Stateful agent: tool execution (parallel or sequential), steering and follow-up queues, lifecycle events, hooks
pi_durable @earendil-works/pi-durable Durable agent harness: conversations, model turns, tool calls and your own state are committed to storage (memory, SQLite, JSONL) before anything is shown, and work resumes after a crash or restart
pi_chord @earendil-works/chord (subset) What pi_durable builds on: explicit cancellation contexts, strict JSON, the transactional JSON tracker and op batches, replicated state, bounded output, an async SQLite layer
pip install pi-ai-python               # httpx + official SDKs: anthropic, openai, google-genai
pip install "pi-ai-python[bedrock]"    # + boto3 for Amazon Bedrock
pip install "pi-ai-python[all]"        # + orjson, websockets, pydantic, boto3

中文说明见 README.zh-CN.md。

import asyncio

from pi_ai import Context, UserMessage
from pi_ai.providers.all import builtin_models


async def main() -> None:
    models = builtin_models()  # every built-in provider; auth comes from env vars such as ANTHROPIC_API_KEY
    model = models.get_model("anthropic", "claude-sonnet-4-5")
    stream = models.stream(model, Context(system_prompt="Be brief.", messages=[UserMessage("Hello!")]))
    async for event in stream:
        if event.type == "text_delta":
            print(event.delta, end="", flush=True)
    message = await stream.result()
    print(f"\n{message.usage.input} in / {message.usage.output} out, ${message.usage.cost.total:.4f}")


asyncio.run(main())
from pi_agent import Agent, AgentInitialState, agent_tool


@agent_tool
async def get_time(timezone: str = "UTC") -> str:
    """Get the current time.

    Args:
        timezone: IANA timezone name.
    """
    ...


agent = Agent(
    initial_state=AgentInitialState(system_prompt="You are helpful.", model=model, tools=[get_time]),
    stream_fn=models.stream_simple,
)
async for event in agent.events("What time is it in Tokyo?"):
    print(event.type)

A durable conversation keeps its transcript, running turns and tool calls in storage. Run the same script again after a crash and resume() picks the work up where it stopped:

import asyncio

from pi_ai import create_models
from pi_ai.providers.openai import openai_provider
from pi_chord import BACKGROUND_CONTEXT
from pi_durable import AssistantEntry, Harness, create_registry
from pi_durable.storage.sqlite.stdlib import open_sqlite_storage


async def main() -> None:
    context = BACKGROUND_CONTEXT
    models = create_models()
    models.set_provider(openai_provider())  # reads OPENAI_API_KEY

    storage = await open_sqlite_storage("./session.sqlite")
    harness = await Harness.open(storage, {"models": models, "registry": create_registry()}, context)
    root = await harness.root(context, agent={"model": {"provider": "openai", "modelId": "gpt-6-sol"}})
    harness.resume()  # continue any run an earlier process left unfinished

    submission = await root.submit({"type": "input", "content": "What is the capital of France?"}, context)
    settled = await submission.wait(context)
    if settled["status"] == "done" and settled["type"] == "input":
        answer = await root.commit(lambda tx: tx.entry(AssistantEntry, settled["answer"]), context)
        print(answer["model"][0].content[0].text if answer else None)
    await harness.close(context)


asyncio.run(main())

pi_durable stores records in the same format as TypeScript pi-durable, so a SQLite or JSONL storage written by one opens in the other. Not ported yet: the built-in coding tools (read/write/edit/bash/image), tool search, images and the code mode extension.

Same API, Python conventions

The port keeps pi's architecture and semantics: the same Models/Provider runtime, the same event protocol (start → text_delta… → done/error), the same transcript model (system prompt and tools carried by system messages), the same auth precedence rules, the same model catalog, and the same agent loop. Names follow Python conventions:

TypeScript Python
createModels(), models.streamSimple(...) create_models(), models.stream_simple(...)
{ apiKey, sessionId, maxTokens } options api_key=..., session_id=..., max_tokens=... keyword arguments (or a dict)
message.stopReason, usage.cacheRead message.stop_reason, usage.cache_read
{ role: "user", content: "hi", timestamp } UserMessage("hi") (timestamp defaults to now)
Type.Object({...}) (TypeBox) Type.Object({...}) (built in) or a Pydantic model
AbortController / signal pi_ai.AbortController / signal=
for await (const e of stream) / await stream.result() async for e in stream / await stream.result()
agent.continue() agent.continue_() (alias agent.resume())

String values that appear on the wire or in persisted transcripts are unchanged ("toolUse", "toolResult", "text_delta", API ids, provider ids), and pi_ai.serialization reads and writes pi's camelCase JSON, so sessions, model definitions and auth.json credential files are interchangeable with TypeScript pi.

Design notes

  • Official vendor SDKs. As in pi, the Anthropic, OpenAI (Chat Completions, Responses, Azure, OpenRouter images), Google (Gemini, Vertex) and Bedrock adapters use the vendors' official SDKs: anthropic, openai, google-genai and boto3 (pi-ai-python[bedrock]). The SDK clients share one pooled httpx.AsyncClient per event loop. APIs that pi calls without an SDK (Mistral, OpenAI Codex, pi-messages, classifiers) use httpx directly.
  • Fast streaming path. Slotted data classes, an allocation-light event queue, zero-copy forwarding between wrapped streams, an incremental partial-JSON parser for tool-call arguments (about 60x faster than re-parsing each delta on large arguments), linear-time accumulation of streamed text, optional orjson decoding, and compiled, cached tool-argument validators. On one core the anthropic-messages adapter processes about 110,000 stream events per second and openai-completions about 70,000, where the openai SDK's SSE decoder is the limit (see benchmarks/).
  • Lazy everything. Model catalogs load per provider on first use; API implementations and OAuth flows import on first request.
  • Async-native cancellation. AbortSignal aborts interrupt pending network reads immediately (task cancellation scoped by abort_scope), and aborted requests end their stream with stop_reason == "aborted" instead of raising.
  • Python-friendly additions. Pydantic models as tool parameter schemas, @agent_tool to build tools from typed functions, Agent.events() as an async iterator, FileCredentialStore (pi's auth.json format with cross-process locking), keyword-argument options, streams that can be created outside an event loop and closed with async with.

Development

uv sync                      # create .venv with the package (editable) and dev tools
uv run pytest                # run all tests (offline; HTTP is mocked)
uv run ruff check . && uv run ruff format --check .
uv run pyright
uv run python benchmarks/bench_partial_json.py
uv run python benchmarks/bench_stream.py
uv run python benchmarks/bench_chord_delta.py
uv run python benchmarks/bench_chord_sqlite.py
uv run python benchmarks/bench_durable_storage.py --quick

The port tracks pi 1.3.0 (@earendil-works/pi-ai, pi-agent-core, pi-durable, chord).

Model catalog data (packages/ai/src/pi_ai/providers/data/*.json) is the generated catalog shipped with @earendil-works/pi-ai 1.3.0.

License

MIT. Based on pi by Mario Zechner and contributors.

Metadata

Release files for pi-ai-python 1.4.0

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

Source distribution (sdist)

Source distribution for pi-ai-python 1.4.0
File Size Uploaded
pi_ai_python-1.4.0.tar.gz 1.2 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for pi-ai-python 1.4.0
File Interpreter ABI Platform
pi_ai_python-1.4.0-py3-none-any.whl Python 3 none any Details

Total release size: 2.0 MB

Release files / pi_ai_python-1.4.0.tar.gz

Download URL pi_ai_python-1.4.0.tar.gz
Size 1.2 MB
Tags Source
SHA-256 checksum
How to use checksums
feeb74851b3c1cf934d2808376e0e4bc13a56632f2d754d84aac65ac61f41d9a
BLAKE2b-256 checksum
How to use checksums
2a185f4c004e86d043e0a3441a70926eb4dcdf6fb64efb1c35243914ba8a4df4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 19, 2026.

Transparency log

Release files / pi_ai_python-1.4.0-py3-none-any.whl

Download URL pi_ai_python-1.4.0-py3-none-any.whl
Size 779.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
09e1bba0122d7247e20266f346803c663bcfb2cd48e9fd288e225f4ec512c9f2
BLAKE2b-256 checksum
How to use checksums
c24019cdb07645423d20780503bb4e1da8d6d18dd14bbe9a7f85c36c2d2ba7d8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 19, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

1.4.0 This release

2 release files

1.3.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