Metadata-Version: 2.4
Name: pi-coding-agent-python-sdk
Version: 0.1.1
Summary: Python SDK facade for Pi Coding Agent sessions, services, resources, tools, and extensions
Requires-Python: >=3.11
Requires-Dist: pydantic<3,>=2.7
Provides-Extra: acp
Requires-Dist: agent-client-protocol<0.11,>=0.10; extra == 'acp'
Provides-Extra: test
Requires-Dist: jsonschema>=4.10; extra == 'test'
Requires-Dist: pytest-asyncio>=0.23; extra == 'test'
Requires-Dist: pytest>=8; extra == 'test'
Description-Content-Type: text/markdown

# Pi Coding Agent Python SDK

Python facade for creating Pi Coding Agent sessions, wiring resources, running the bundled TypeScript bridge, exposing MCP servers, and serving the agent through ACP.

The package published to PyPI is `pi-coding-agent-python-sdk`. The import package is `pi_coding_agent`.

## Install

```bash
pip install pi-coding-agent-python-sdk
```

ACP support is optional:

```bash
pip install "pi-coding-agent-python-sdk[acp]"
```

Provider-backed sessions use the bundled bridge worker and require either Node.js or Bun on `PATH`. The explicit `backend="in_process"` mode is a local deterministic mode for tests and offline examples.

## Quick Start

```python
import asyncio

from pi_coding_agent import MessageUpdateEvent, create_agent_session


async def main() -> None:
    result = await create_agent_session(cwd=".", backend="in_process")
    session = result.session
    try:
        session.subscribe(
            lambda event: print(event.assistant_message_event.delta, end="")
            if isinstance(event, MessageUpdateEvent)
            else None
        )
        await session.prompt("List the files in this directory.")
    finally:
        await session.dispose()


asyncio.run(main())
```

This first example is a local smoke test. For a provider-backed session, use `HarnessConfig` and keep secrets in environment variables:

```python
import asyncio

from pi_coding_agent import HarnessConfig, create_agent_session_from_config


config = HarnessConfig.from_dict(
    {
        "run": {"cwd": ".", "backend": "node"},
        "env": {
            "required": ["NOVITA_API_KEY"],
            "optional": ["NOVITA_BASE_URL"],
        },
        "model": {
            "provider": "novita",
            "id": "deepseek/deepseek-v4-flash",
            "base_url": "https://api.novita.ai/v3/openai",
            "api_key_env": "NOVITA_API_KEY",
            "context_window": 128000,
            "max_tokens": 32000,
            "reasoning": True,
            "compat": {
                "thinkingFormat": "deepseek",
                "requiresReasoningContentOnAssistantMessages": True,
            },
        },
        "provider_options": {
            "temperature": 0,
            "tool_choice": "auto",
            "parallel_tool_calls": True,
        },
        "tools": {"allow": ["read", "write", "edit", "bash", "grep", "find", "ls"]},
    }
)


async def main() -> None:
    result = await create_agent_session_from_config(config)
    try:
        await result.session.prompt("Inspect the project and summarize the test layout.")
    finally:
        await result.session.dispose()


asyncio.run(main())
```

## Harness TOML

`HarnessConfig` can load and dump TOML. It covers runtime selection, model/provider setup, environment passthrough, tool allowlists, resources, extensions, skills, MCP servers, hooks, and session storage.

```toml
version = 1

[run]
cwd = "."
backend = "node"

[js]
runtime = "bun"
request_timeout_sec = 30
tool_timeout_sec = 60
compact_timeout_sec = 300

[env]
required = ["NOVITA_API_KEY"]
optional = ["NOVITA_BASE_URL"]

[model]
provider = "novita"
id = "deepseek/deepseek-v4-flash"
base_url = "https://api.novita.ai/v3/openai"
api_key_env = "NOVITA_API_KEY"
context_window = 128000
max_tokens = 32000
reasoning = true

[model.compat]
thinkingFormat = "deepseek"
requiresReasoningContentOnAssistantMessages = true

[provider_options]
temperature = 0
tool_choice = "auto"
parallel_tool_calls = true

[tools]
allow = ["read", "write", "edit", "bash", "grep", "find", "ls"]

[mcp.servers.time]
command = "uvx"
args = ["mcp-server-time"]
```

```python
import asyncio

from pi_coding_agent import create_agent_session_from_config


async def main() -> None:
    result = await create_agent_session_from_config("pi-harness.toml")
    try:
        await result.session.prompt("What time tools are available?")
    finally:
        await result.session.dispose()


asyncio.run(main())
```

## Main Capabilities

- Session creation through `create_agent_session`, `create_agent_session_from_config`, `create_agent_session_services`, and `create_agent_session_runtime`.
- Built-in tools: `read`, `write`, `edit`, `bash`, `grep`, `find`, and `ls`.
- Python custom tools through `ToolDefinition`.
- TypeScript extension paths, package extension sources, and Python extension factories.
- Skills from local paths, GitHub sources through `npx skills add`, and Pi package-loader sources.
- Prompt templates, `AGENTS.md` discovery, system prompt overrides, and append-system-prompt files.
- MCP server configuration through `McpConfig` or TOML.
- Hooks for session, prompt, tool, compact, and stop events.
- Session JSON serialization and restoration.
- ACP server integration through `pi-coding-agent-acp`.

## Documentation

- [Harness Config](docs/harness-config.md)
- [Resources, Extensions, Skills, MCP, And Hooks](docs/resources.md)
- [ACP Integration](docs/acp.md)
- [Development And Release Notes](docs/development.md)
- [Example Parity Matrix](examples/sdk/PARITY.md)
- [Bridge Validation](examples/sdk/BRIDGE_VALIDATION.md)

## Development

Run the default suite with `uv`:

```bash
uv run -m unittest discover -s tests
```

Build and inspect the package:

```bash
uv build
uv run --with twine python -m twine check dist/*
```

The test suite is designed to run without provider credentials by default. Provider-backed tests are opt-in and should use environment variables, not checked-in secrets.
