Skip to main content

pi-python

CI PyPI Python License

Unofficial project: this repository is not affiliated with, endorsed by, or maintained by the official pi project or its maintainers.

Python port of pi-agent-core from the pi project, with LangChain replacing pi-ai for LLM calls.

The loop semantics, event protocol, and tool execution are faithful ports of pi; LangChain is only a StreamFn boundary adapter — never a replacement for the agent loop.

This repository is a monorepo containing:

Python packages (PyPI):

  • pi-agent-core-lc / pi_agent_core: lightweight core loop, messages, tools, adapters.
  • pi-agent-harness-lc / pi_agent_harness: harness runtime, sessions, queues, hooks, compaction, skills/templates, and local execution env.
  • pi-agent-cli-lc / pi_agent_cli: standard ACP coding agent (python -m pi_agent_cli, headless -p).

Rust TUI (beta — prebuilt binary in GitHub Releases):

  • zypi: full-screen terminal UI for interactive coding-agent sessions. Vendored fork of grok-build (Apache-2.0), with all x.ai/* vendor extensions removed. See TUI & Code-Agent Guide for details.

Status

Component Status Distribution
pi-agent-core-lc Stable PyPI
pi-agent-harness-lc Stable PyPI
pi-agent-cli-lc Beta PyPI
zypi (Rust TUI) Beta GitHub Releases (Linux x86_64)

Features

Core runtime (Phase 1)

  • Agent — stateful agent with steering / follow-up queues, abort, subscribe() event barrier
  • agent_loop — tool execution loop with pi-compatible event protocol (parallel/sequential tools, terminate semantics, should_stop_after_turn, prepare_next_turn)
  • LangChain StreamFn adapter (langchain_stream) for OpenAI / Anthropic / DeepSeek-style / any init_chat_model provider
  • Mock stream for tests — the whole suite runs without API keys

Production hardening (Phase 2 / 2.5)

  • Cross-provider message replay (transform_messages: tool-call id normalization, thinking downgrade, image stripping)
  • Usage & cost tracking (accumulated across stream chunks, correct for all three real-world reporting shapes) + CostCalculator
  • Thinking/reasoning: provider param mapping (reasoning_effort / Anthropic thinking budgets), streamed thinking_delta events, Anthropic signature replay, DeepSeek-style reasoning_content
  • Stream-level retries before the first token (exponential backoff + jitter, Retry-After aware)
  • Runaway protection: max_turns (raises MaxTurnsExceededError) and per-tool tool_timeout
  • Guardrail hooks: before_llm_call (with a ContextBudget token signal — the compaction hook point), after_llm_call (tripwire on raise), on_agent_end
  • Observability: on_payload / on_response hooks; every event carries run_id / turn_id
  • Granular stream events: text_start/end, thinking_start/end, toolcall_start/end (plus deltas)
  • Structured output: response_schema (pydantic model or JSON schema) → parsed AssistantMessage.structured_output
  • Tool-result images: Anthropic native blocks, user-message fallback elsewhere, stripped when supports_images=False
  • OpenAI-compatible gateways via Model.base_url (SiliconFlow, vLLM, DeepSeek, ...)

Tool ecosystem (P6)

  • Built-in coding tools (pi_agent_core.coding_tools): read / bash / edit / write / grep / find / ls with pi-faithful truncation notices and details payloads
  • LangChain BaseTool → AgentTool adapter (from_langchain_tool) — MCP tools via langchain-mcp-adapters work out of the box

Coding Agent CLI (Phase 4 — beta)

  • pi_agent_cli: standard ACP coding agent over AgentHarness — no x.ai/* vendor extensions
  • Headless mode: python -m pi_agent_cli -p "prompt" for scripting and CI
  • /new, /resume, /quit session commands; @ local directory listing
  • pi-aligned system prompt engine with tool contributions, AGENTS.md context files, <available_skills> format

TUI — zypi (Phase 4 — beta)

  • Full-screen Rust terminal UI for interactive coding-agent sessions
  • Spawns the Python ACP agent (python -m pi_agent_cli) as the backend
  • Session management, markdown rendering, Mermaid diagrams, MCP support
  • Prebuilt Linux x86_64 binary in GitHub Releases; build from source for other platforms
  • See TUI & Code-Agent Guide for setup and usage

FrontierHarness Evaluation (30-task benchmark)

  • 21 Terminal-Bench + 9 DeepSWE industrial tasks; Windows local + WSL2 Docker sandbox runtimes
  • Side-by-side comparison with official Pi; full report: FRONTIER-HARNESS-30-EVAL-REPORT.md

Install

Python packages (PyPI)

pip install pi-agent-core-lc
pip install pi-agent-harness-lc    # optional: session/harness runtime
pip install pi-agent-cli-lc        # optional: ACP stdio / headless agent

# Optional LLM providers:
pip install pi-agent-core-lc[openai]      # ChatOpenAI
pip install pi-agent-core-lc[anthropic]   # ChatAnthropic
pip install pi-agent-core-lc[deepseek]    # ChatDeepSeek / OpenAI-compatible gateways
pip install pi-agent-core-lc[all]         # all providers + harness + cli
Development install (editable)
pip install -e ".[dev]"
pip install -e "./packages/pi-agent-harness"
pip install -e "./packages/pi-agent-cli"

TUI binary (zypi) — beta

Download the prebuilt Linux x86_64 binary from GitHub Releases:

# Download and install (Linux x86_64)
curl -L -o zypi https://github.com/zy1233/pi-python/releases/latest/download/zypi-linux-x86_64
chmod +x zypi
sudo mv zypi /usr/local/bin/

# Or build from source (requires Rust toolchain)
cd tui && cargo build --profile release-dist -p pi-pager-bin
# binary at target/release-dist/zypi

After installing, set up config and start the TUI — see TUI & Code-Agent Guide.

Quick start

import asyncio
from pi_agent_core import Agent, Model
from pi_agent_core.adapters import langchain_stream


async def main():
    agent = Agent(
        initial_state={
            "system_prompt": "You are a helpful assistant.",
            "model": Model(provider="openai", model_id="gpt-4o-mini"),
        },
        stream_fn=langchain_stream,
    )

    agent.subscribe(lambda event, signal: print(event.type))

    await agent.prompt("Hello!")
    await agent.wait_for_idle()


asyncio.run(main())

Requires OPENAI_API_KEY (or the env var for your provider).

OpenAI-compatible gateways

Point Model.base_url at any OpenAI-compatible endpoint. Use provider="deepseek" when the endpoint streams thinking as reasoning_content (SiliconFlow, DeepSeek, most vLLM gateways) so it surfaces as thinking_delta events instead of being dropped:

model = Model(
    provider="deepseek",
    model_id="Qwen/Qwen3-8B",
    base_url="https://api.siliconflow.cn/v1",
    context_window=32_000,
)
agent = Agent(initial_state={"model": model}, stream_fn=langchain_stream)
# pass the key explicitly or via env: DEEPSEEK_API_KEY

Structured output

from pydantic import BaseModel


class Person(BaseModel):
    name: str
    age: int


agent = Agent(
    initial_state={"model": model},
    stream_fn=langchain_stream,
    response_schema=Person,  # or a JSON schema dict
)
await agent.prompt("Invent a fictional person.")
await agent.wait_for_idle()

agent.messages[-1].structured_output  # {'name': ..., 'age': ...} (None if not parseable)

Schema instructions are injected into the system prompt for every provider; OpenAI-style providers additionally get native response_format enforcement. Streaming stays intact — the JSON text still flows as text_delta events.

Production configuration

from pi_agent_core import Agent, ContextBudget


def on_payload(payload: dict):  # outgoing request (pre-call)
    log.debug("LLM call", model=payload["model"], tools=len(payload["tools"]))


async def before_llm_call(context, budget: ContextBudget | None):
    if budget and budget.fraction > 0.8:
        return await my_compactor.compact(context)  # durably replaces loop context
    return None


def after_llm_call(context, message):
    if contains_pii(message):  # guardrail tripwire: raise to abort the run
        raise PiiDetected()


agent = Agent(
    initial_state={"model": model, "tools": tools},
    stream_fn=langchain_stream,
    max_turns=25,  # raises MaxTurnsExceededError -> agent.error_message
    tool_timeout=120.0,  # per tool call, seconds; times out into an error tool result
    max_retries=3,  # stream-level retries before the first token
    on_payload=on_payload,
    before_llm_call=before_llm_call,
    after_llm_call=after_llm_call,
)

Runnable version: examples/production_agent.py.

Built-in coding tools

A port of pi's coding-agent tool suite lives in pi_agent_core.coding_tools, decoupled from the core runtime (tools consume the loop; they are not part of it). Factories bind each tool to a working directory:

from pi_agent_core.coding_tools import create_coding_tools, create_read_only_tools

tools = create_coding_tools("/path/to/project")  # read / bash / edit / write
audit = create_read_only_tools("/path/to/project")  # read / grep / find / ls
agent = Agent(initial_state={"model": model, "tools": tools}, stream_fn=langchain_stream)
Tool Group Behavior
read both Text (2000-line / 50KB truncation, offset/limit paging) and images (magic-number sniffing → image blocks)
edit coding Exact-text replacement with unique-match guarantee, fuzzy fallback (smart quotes/dashes/trailing whitespace), CRLF/BOM round-trip, unified-diff details
write coding Create/overwrite with automatic parent dirs; per-file mutation queue serializes concurrent writes
bash coding Real shell (bash -c; Git Bash on Windows, shell_path override), merged stdout+stderr, tail truncation with full output spilled to a temp file (details.fullOutputPath), timeout/abort kill the whole process tree, 100ms-throttled streaming updates
grep read-only ripgrep-first (--json streaming, kills the process at the match limit); pure-Python fallback when rg is missing
find read-only Pure-Python glob walk; basename patterns vs any-depth path patterns (src/**/*.py)
ls read-only Case-insensitive sort, / dir suffix, dotfiles, entry limit

Groups mirror pi: create_coding_tools(cwd) (read/bash/edit/write — full file operations plus command execution) and create_read_only_tools(cwd) (read/grep/find/ls — inspection with a no-modification guarantee). Per-tool create_*_tool(cwd) factories and create_tool(name, cwd) / create_all_tools(cwd) cover custom mixes. Truncation limits are pi's (2000 lines / 50KB, grep lines capped at 500 chars) with actionable notices ("Use offset=N to continue") so the model can page through anything that was cut.

Using LangChain / MCP tools

Any LangChain BaseTool — including MCP tools produced by langchain-mcp-adapters — plugs into the same loop through the adapter:

from langchain_core.tools import tool
from pi_agent_core.adapters import from_langchain_tool, from_langchain_tools


@tool
def get_weather(city: str) -> str:
    """Get the current weather for a city."""
    return f"Sunny in {city}"


agent = Agent(
    initial_state={"model": model, "tools": [from_langchain_tool(get_weather)]},
    stream_fn=langchain_stream,
)

Parameter schemas come from tool_call_schema (LangChain-injected arguments are excluded); results normalize to pi content blocks (plain strings, content-block lists, base64 images); content_and_artifact artifacts land in details["artifact"]; tool exceptions bubble into is_error=True tool results that the model can react to.

Custom messages

AgentMessage is structurally open: anything with a string role flows through the loop and persists to the session (AgentMessageProtocol, a runtime-checkable Protocol in pi_agent_harness). The harness ships four custom roles — bashExecution, custom, branchSummary, compactionSummary — and harness_convert_to_llm decides how each role reaches the LLM; unknown roles are dropped at that boundary:

from pydantic import BaseModel
from pi_agent_harness import AgentMessageProtocol
from pi_agent_harness.messages import BashExecutionMessage, harness_convert_to_llm

# Built-in custom role: record a shell run in the session/context
bash = BashExecutionMessage(command="pytest -q", output="97 passed", exitCode=0, timestamp=0)
await harness.append_message(bash)  # persisted; replayed to the LLM as a user message


# Your own role: any object with `role: str` satisfies the protocol
class DeployNote(BaseModel):
    role: str = "deployNote"
    environment: str
    timestamp: int


assert isinstance(DeployNote(environment="staging", timestamp=0), AgentMessageProtocol)

To make a custom role visible to the LLM, wrap harness_convert_to_llm (or pass your own convert_to_llm to the core loop) and map it to a UserMessage — the same pattern the harness uses for its own roles.

Events

Agent events (all carry run_id and a 1-based turn_id):

agent_start → turn_start → message_start/end (user)
→ message_start(assistant) → message_update* → message_end(assistant)
→ [tool_execution_start/update/end → message_start/end (toolResult)]
→ turn_end → ... → agent_end

message_update wraps the granular assistant-stream events: text_start/delta/end, thinking_start/delta/end, toolcall_start/delta/end. End events carry the aggregate (content full text / complete tool_call block).

Test

uv run --extra dev --extra harness python -m pytest  # 418 tests, no API keys needed
ruff check . && ruff format --check .

Real-API validation (key via env only; skipped when unset):

Purpose Command Env vars
Automated regression pytest -m real_llm -v REAL_LLM_API_KEY, optional REAL_LLM_BASE_URL / REAL_LLM_MODEL
Manual pre-release smoke python scripts/smoke_real_api.py SMOKE_API_KEY (or REAL_LLM_API_KEY), SMOKE_BASE_URL, SMOKE_MODEL
pi TUI foundation case python scripts/smoke_pelican.py REAL_LLM_API_KEY; saves SVG to ~/.pi-python/benchmarks/pelican/ — see docs/benchmarks/PELCAN-BICYCLE.md

Use .venv-test-real for pytest real-LLM tests; the smoke script can run from the main .venv.

Documentation

Document Contents
AGENTS.md Project overview, module map, invariants, current status
docs/DESIGN.md Project-wide architecture and module design
docs/PLAN/PLAN-PHASE1.md Phase 1 original planning document (historical)
docs/AUDIT/AUDIT-2026-07-02.md Core-layer audit: findings, fixes, Phase 2.5 enhancements
docs/AUDIT/AUDIT-H1.md ~ H4 Harness batch audits (H1 session, H2 runtime, H3 compaction, H4 skills/env)
P0 TUI spike grok pager x.ai/* strip inventory
Phase 2 spec Usage/cost, thinking/reasoning, transform_messages
Phase 3 spec AgentHarness: sessions, compaction, skills, templates, ExecutionEnv
P6 spec Built-in coding tools + LangChain adapter
Phase 4 spec Coding Agent CLI: forked grok TUI + standard ACP agent
Phase 5 spec Coding Agent prompt engine: system prompt assembly
TUI & Code-Agent Guide Installation, configuration, usage for zypi TUI and pi_agent_cli
Windows notes Phase 4 Windows setup, WSL TUI build, spawn/config
Benchmark report FrontierHarness 30-task evaluation & Pi comparison

Concept mapping (pi → Python)

pi (TypeScript) pi-python
@earendil-works/pi-agent-core pi_agent_core
packages/agent/src/harness pi_agent_harness
@earendil-works/pi-ai streamSimple langchain_stream
AgentMessage UserMessage / AssistantMessage / ToolResultMessage + custom
Model.baseUrl Model.base_url
onPayload / onResponse on_payload / on_response
agent.prompt() await agent.prompt()
agent.continue() await agent.continue_()

Roadmap

Completed

  • Phase 1 (MVP loop) — done: Agent + agent_loop + event protocol + tool execution
  • Phase 2 (production enhancements) — done: transform_messages, usage/cost, thinking/reasoning
  • Phase 2.5 (core hardening) — done: retries, runaway protection, observability, granular events, guardrail hooks, ContextBudget, structured output, tool-result images
  • Phase 3 (AgentHarness) — done: H1 session tree, H2 runtime, H3 compaction/tree navigation, H4 skills/templates/system prompt/LocalExecutionEnv (design doc)
  • P6 (tool ecosystem) — done: all 7 built-in tools (read/bash/edit/write/grep/find/ls), group factories, and the LangChain BaseTool adapter (design doc)
  • Phase 4 (Coding Agent CLI — beta) — done: tui/ vendored grok-build fork (Apache-2.0); pi_agent_cli standard ACP agent; TUI binary zypi; x.ai/* vendor RPCs removed; session management (/new /resume /quit); headless -p; config.toml + Windows notes (design doc, Windows, TUI guide)
  • Phase 5 (Coding Agent prompt engine) — done: pi-aligned build_system_prompt + tool contributions + context files + <available_skills> (design doc)
  • FrontierHarness Eval — done: 30-task benchmark (21 Terminal-Bench + 9 DeepSWE); Windows + WSL Docker runtimes; side-by-side Pi comparison (report)

Next

  • Phase 6 (Extended integrations) — planned: native MCP client, git-aware context injection, multi-provider production testing matrix
  • TUI platform expansion — planned: prebuilt binaries for macOS (arm64/x86_64) and Windows; auto-update support

License

Python packages (pi-agent-core-lc, pi-agent-harness-lc, pi-agent-cli-lc) are MIT.

The tui/ directory is a vendored fork of xai-org/grok-build and remains Apache License 2.0. See tui/LICENSE, tui/NOTICE, and tui/THIRD-PARTY-NOTICES. tui/ is not included in Python sdists or wheels.

Metadata

Release files for pi-agent-core-lc 0.3.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-agent-core-lc 0.3.0
File Size Uploaded
pi_agent_core_lc-0.3.0.tar.gz 1.8 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for pi-agent-core-lc 0.3.0
File Interpreter ABI Platform
pi_agent_core_lc-0.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 1.9 MB

Release files / pi_agent_core_lc-0.3.0.tar.gz

Download URL pi_agent_core_lc-0.3.0.tar.gz
Size 1.8 MB
Tags Source
SHA-256 checksum
How to use checksums
4e8909e31671ba883b1694283152e8e294721d0e7c11a7d3a007786d6fcb5e4c
BLAKE2b-256 checksum
How to use checksums
0ddb1d4df9764177c1cfc625bc242e7feda805d82e914662f4019695843013a4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / pi_agent_core_lc-0.3.0-py3-none-any.whl

Download URL pi_agent_core_lc-0.3.0-py3-none-any.whl
Size 119.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2256cd9e08ed07f44f64d726429984f0b883184c6197cd7471a27a0285bcaceb
BLAKE2b-256 checksum
How to use checksums
38f0caca60e8cee13c2c53b5a8e08f4ac39060afa5539c979da8013fbeb3bcba
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

0.4.0

2 release files

This release

0.3.0 This release

2 release files

0.2.0

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