diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml new file mode 100644 index 0000000..be7ef46 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -0,0 +1,69 @@ +name: Bug Report +description: Tell us about a regression or defect in the ACP Python SDK. +title: "bug: " +labels: ["bug"] +body: + - type: markdown + attributes: + value: > + Thanks for filing a detailed bug. Fill out every section so we can + reproduce the issue quickly and keep the SDK solid. + + - type: textarea + id: summary + attributes: + label: Summary + description: What went wrong? Keep it short but specific. + placeholder: "Streaming updates stop after the second prompt…" + validations: + required: true + + - type: textarea + id: repro + attributes: + label: Reproduction steps + description: > + Commands, code, or payloads that trigger the bug. Include any relevant + input files or snippets (redact secrets). + validations: + required: true + + - type: textarea + id: expected + attributes: + label: Expected result + placeholder: "Tool call should finish and emit a completed status…" + validations: + required: true + + - type: textarea + id: actual + attributes: + label: Actual result + placeholder: "Agent hangs and no further session/update payloads arrive…" + validations: + required: true + + - type: input + id: versions + attributes: + label: Versions / environment + description: > + Include SDK version, ACP schema tag (if pinned), Python version, and OS. + placeholder: "sdk 0.5.1 (schema v0.4.7), Python 3.12.2 on macOS 14.4" + validations: + required: true + + - type: textarea + id: logs + attributes: + label: Logs & screenshots + description: Paste relevant stack traces, JSON snippets, or console output. + render: shell + + - type: checkboxes + id: willing-to-pr + attributes: + label: Open to submitting a fix? + options: + - label: I’m willing to open a PR for this bug. diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..9495c0b --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,8 @@ +blank_issues_enabled: false +contact_links: + - name: Ask a question + url: https://github.com/agentclientprotocol/python-sdk/discussions/new?category=q-a + about: Usage questions, architecture ideas, and doc clarifications live best in Discussions. + - name: Read the docs + url: https://agentclientprotocol.github.io/python-sdk/ + about: The published docs cover quickstart steps, contrib helpers, and release workflows. diff --git a/.github/ISSUE_TEMPLATE/feature-request.yml b/.github/ISSUE_TEMPLATE/feature-request.yml new file mode 100644 index 0000000..bd17e70 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-request.yml @@ -0,0 +1,50 @@ +name: Feature Request +description: Pitch an improvement for the ACP Python SDK docs, runtime, or tooling. +title: "feat: " +labels: ["enhancement"] +body: + - type: markdown + attributes: + value: > + Feature requests work best when they focus on the problem first. Tell us + what you’re trying to achieve and why existing APIs aren’t enough. + + - type: textarea + id: problem + attributes: + label: Problem statement + description: > + What use case is blocked? Include relevant transports, helpers, or user + journeys. + placeholder: "Need a helper to batch tool call updates when streaming…" + validations: + required: true + + - type: textarea + id: proposal + attributes: + label: Proposed solution + description: > + Sketch the API or behaviour you’d like to see. Code snippets welcome. + validations: + required: true + + - type: textarea + id: alternatives + attributes: + label: Alternatives considered + description: > + Mention workarounds you’ve tried or other approaches we should weigh. + + - type: textarea + id: extra + attributes: + label: Additional context + description: Links, screenshots, related issues, etc. + + - type: checkboxes + id: willing-to-help + attributes: + label: Can you help build it? + options: + - label: I can contribute code or docs for this request. diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..8b7b80b --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,35 @@ +## Summary + + + + +## Related issues + + + + +## Testing + + + + +## Docs & screenshots + + + + +## Checklist + +- [ ] Conventional Commit title (e.g. `feat:`, `fix:`). +- [ ] Tests cover the change or are not required (explain above). +- [ ] Docs/examples updated when behaviour is user-facing. +- [ ] Schema regenerations (`make gen-all`) are called out if applicable. diff --git a/AGENTS.md b/AGENTS.md index fdc7f48..a2927e4 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,35 +1,47 @@ -# Repository Guidelines - -## Project Structure & Module Organization -- `src/acp/`: runtime package exposing agent/client abstractions, transports, and the generated `schema.py`. -- `schema/`: upstream JSON schema sources; regenerate Python bindings with `make gen-all`. -- `examples/`: runnable scripts (`echo_agent.py`, `client.py`, `gemini.py`, etc.) demonstrating stdio orchestration patterns. -- `tests/`: pytest suite, including opt-in Gemini smoke checks under `tests/test_gemini_example.py`. -- `docs/`: MkDocs content powering the hosted documentation. - -## Build, Test, and Development Commands -- `make install` — provision the `uv` virtualenv and install pre-commit hooks. -- `make check` — run Ruff linting/formatting, type analysis, dependency hygiene, and lock verification. -- `make test` — execute `pytest` (with doctests) inside the managed environment. -- `make gen-all` — refresh protocol artifacts when the ACP schema version advances (`ACP_SCHEMA_VERSION=` to pin an upstream tag). - -## Coding Style & Naming Conventions -- Target Python 3.10+ with four-space indentation and type hints on public APIs. -- Ruff enforces formatting and lint rules (`uv run ruff check`, `uv run ruff format`); keep both clean before publishing. -- Prefer dataclasses or generated Pydantic models from `acp.schema` over ad-hoc dicts. Place shared utilities in `_`-prefixed internal modules. -- Prefer the builders in `acp.helpers` (for example `text_block`, `start_tool_call`) when constructing ACP payloads. The helpers instantiate the generated Pydantic models for you, keep literal discriminator fields out of call sites, and stay in lockstep with the schema thanks to the golden tests (`tests/test_golden.py`). - -## Testing Guidelines -- Tests live in `tests/` and must be named `test_*.py`. Use `pytest.mark.asyncio` for coroutine coverage. -- Run `make test` (or `uv run python -m pytest`) prior to commits; include reproducing steps for any added fixtures. -- Gemini CLI coverage is disabled by default. Set `ACP_ENABLE_GEMINI_TESTS=1` (and `ACP_GEMINI_BIN=/path/to/gemini`) to exercise `tests/test_gemini_example.py`. - -## Commit & Pull Request Guidelines -- Follow Conventional Commits (`feat:`, `fix:`, `docs:`, etc.) with succinct scopes, noting schema regenerations when applicable. -- PRs should describe exercised agent behaviours, link relevant issues, and include output from `make check` or focused pytest runs. -- Update documentation and examples whenever public APIs or transport behaviours change, and call out environment prerequisites for new integrations. +# Repository Handbook + +Use this page as the quick orientation for the Python SDK repo. It mirrors the tone of the main README/index and surfaces what you need without hunting through multiple docs. + +## Repo Map + +| Path | Why it exists | +| --- | --- | +| `src/acp/` | Runtime package: agent/client bases, transports, helpers, schema bindings, contrib utilities | +| `schema/` | Upstream JSON schema sources (regenerate with `make gen-all`) | +| `examples/` | Runnable scripts such as `echo_agent.py`, `client.py`, `gemini.py`, `duet.py` | +| `tests/` | Pytest suite, including optional Gemini smoke tests in `tests/test_gemini_example.py` | +| `docs/` | MkDocs content published at `agentclientprotocol.github.io/python-sdk/` | + +## Daily Commands + +| Need | Command | +| --- | --- | +| Bootstrap env + pre-commit | `make install` | +| Format, lint, types, deps | `make check` | +| Test suite (pytest + doctest) | `make test` | +| Regenerate schema + bindings | `ACP_SCHEMA_VERSION= make gen-all` | + +## Style Guardrails + +- Target Python 3.10+ and keep public APIs typed. +- Ruff handles formatting + linting (`uv run ruff format` / `check`)—keep both clean before pushing. +- Reach for the generated Pydantic models and helpers (e.g. `text_block`, `start_tool_call`) instead of hand-crafting dicts; helpers stay aligned with the schema via `tests/test_golden.py`. +- Place reusable internals in `_`-prefixed modules. + +## Testing Expectations + +- Tests live under `tests/` and follow the `test_*.py` naming. Mark async tests with `pytest.mark.asyncio`. +- Run `make test` (or `uv run python -m pytest`) before committing and include reproduction steps for new fixtures. +- Gemini CLI checks are opt-in: set `ACP_ENABLE_GEMINI_TESTS=1` and optionally `ACP_GEMINI_BIN=/path/to/gemini` to exercise `tests/test_gemini_example.py`. + +## PR Checklist + +- Use Conventional Commit prefixes (`feat:`, `fix:`, `docs:`, etc.) and call out schema regenerations explicitly. +- Summarise exercised behaviours, link related issues, and attach `make check` / targeted pytest output in PR descriptions. +- Update docs/examples when user-visible APIs or transports change, and document any new environment requirements. ## Agent Integration Tips -- Bootstrap agents from `examples/echo_agent.py` or `examples/agent.py`; pair with `examples/client.py` for round-trip validation. -- Use `spawn_agent_process` / `spawn_client_process` to embed ACP parties directly in Python applications. -- Validate new transports against `tests/test_rpc.py` and, when applicable, the Gemini example to ensure streaming updates and permission flows stay compliant. + +- Start new agents from `examples/echo_agent.py` or `examples/agent.py`; pair them with `examples/client.py` for loopback validation. +- `spawn_agent_process` / `spawn_client_process` embed ACP parties inside Python apps without hand-wiring stdio. +- Validate new transports against `tests/test_rpc.py` and (when relevant) the Gemini example to ensure streaming + permission flows stay compliant. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e4662c0..e8f5ac6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,126 +1,47 @@ -# Contributing to `agentclientprotocol/python-sdk` +# Contributing -Contributions are welcome, and they are greatly appreciated! -Every little bit helps, and credit will always be given. +Thanks for helping improve the Agent Client Protocol Python SDK! This guide mirrors the concise tone of the README/index so you can skim it quickly and get back to building. -You can contribute in many ways: +## Ways to help -# Types of Contributions +- **Report bugs** — file an issue with repro steps, OS + Python versions, and any environment toggles. +- **Improve docs/examples** — clarify workflows, add integration notes, or document a new transport. +- **Fix issues** — search for `bug` / `help wanted` labels or tackle anything that affects your integration. +- **Propose features** — describe the use case, API shape, and constraints so we can scope the work together. -## Report Bugs +## Filing great issues -Report bugs at https://github.com/agentclientprotocol/python-sdk/issues +When reporting a bug or requesting a feature, include: -If you are reporting a bug, please include: +- The ACP schema / SDK version you’re using. +- How to reproduce the behaviour (commands, inputs, expected vs. actual). +- Logs or payload snippets when available (scrub secrets). -- Your operating system name and version. -- Any details about your local setup that might be helpful in troubleshooting. -- Detailed steps to reproduce the bug. +## Local workflow -## Fix Bugs +1. **Fork & clone** your GitHub fork: `git clone git@github.com:/python-sdk.git`. +2. **Bootstrap tooling** inside the repo root: `make install`. This provisions `uv`, syncs deps, and installs pre-commit hooks. +3. **Create a topic branch:** `git checkout -b feat-my-improvement`. +4. **Develop + document:** + - Keep code typed (Python 3.10+), prefer generated models/helpers over dicts. + - Update docs/examples when user-facing behaviour shifts. +5. **Run the test gauntlet:** + ```bash + make check # formatting, lint, type analysis, deps + make test # pytest + doctests + ``` + Optional: `ACP_ENABLE_GEMINI_TESTS=1 make test` when you have the Gemini CLI available. +6. **(Optional) Cross-Python smoke:** `tox` if you want the same matrix CI runs. +7. **Commit + push:** `git commit -m "feat: add better tool call helper"` followed by `git push origin `. -Look through the GitHub issues for bugs. -Anything tagged with "bug" and "help wanted" is open to whoever wants to implement a fix for it. +## Pull request checklist -## Implement Features +- [ ] PR title follows Conventional Commits. +- [ ] Tests cover the new behaviour (or the reason they’re not needed is documented). +- [ ] `make check` / `make test` output is attached or referenced. +- [ ] Docs and examples reflect user-visible changes. +- [ ] Any schema regeneration (`make gen-all`) is called out explicitly. -Look through the GitHub issues for features. -Anything tagged with "enhancement" and "help wanted" is open to whoever wants to implement it. +## Need help? -## Write Documentation - -This project could always use more documentation, whether as part of the official docs, in docstrings, or even on the web in blog posts, articles, and such. - -## Submit Feedback - -The best way to send feedback is to file an issue at https://github.com/agentclientprotocol/python-sdk/issues. - -If you are proposing a new feature: - -- Explain in detail how it would work. -- Keep the scope as narrow as possible, to make it easier to implement. -- Remember that this is a volunteer-driven project, and that contributions - are welcome :) - -# Get Started! - -Ready to contribute? Here's how to set up the project for local development. -Please note this documentation assumes you already have `uv` and `Git` installed and ready to go. - -1. Fork the `agentclientprotocol/python-sdk` repo on GitHub. - -2. Clone your fork locally: - -```bash -cd -git clone git@github.com:YOUR_NAME/python-sdk.git -``` - -3. Now we need to install the environment. Navigate into the directory - -```bash -cd python-sdk -``` - -Then, install and activate the environment with: - -```bash -uv sync -``` - -4. Install pre-commit to run linters/formatters at commit time: - -```bash -uv run pre-commit install -``` - -5. Create a branch for local development: - -```bash -git checkout -b name-of-your-bugfix-or-feature -``` - -Now you can make your changes locally. - -6. Don't forget to add test cases for your added functionality to the `tests` directory. - -7. When you're done making changes, check that your changes pass the formatting tests. - -```bash -make check -``` - -Now, validate that all unit tests are passing: - -```bash -make test -``` - -9. Before raising a pull request you should also run tox. - This will run the tests across different versions of Python: - -```bash -tox -``` - -This requires you to have multiple versions of python installed. -This step is also triggered in the CI/CD pipeline, so you could also choose to skip this step locally. - -10. Commit your changes and push your branch to GitHub: - -```bash -git add . -git commit -m "Your detailed description of your changes." -git push origin name-of-your-bugfix-or-feature -``` - -11. Submit a pull request through the GitHub website. - -# Pull Request Guidelines - -Before you submit a pull request, check that it meets these guidelines: - -1. The pull request should include tests. - -2. If the pull request adds functionality, the docs should be updated. - Put your new functionality into a function with a docstring, and add the feature to the list in `README.md`. +Open a discussion or ping us in the ACP Zulip if you’re stuck on design decisions, transport quirks, or schema questions. We’d rather collaborate early than rework later. diff --git a/README.md b/README.md index 51f8cfc..6bab6d0 100644 --- a/README.md +++ b/README.md @@ -1,199 +1,75 @@ - + Agent Client Protocol # Agent Client Protocol (Python) -Python SDK for the Agent Client Protocol (ACP). Build agents that speak ACP over stdio so tools like Zed can orchestrate them. +Build ACP-compliant agents and clients in Python with generated schema models, asyncio transports, helper builders, and runnable demos. -> Each release tracks the matching ACP schema version. Contributions that improve coverage or tooling are very welcome. - -**Highlights** - -- Generated `pydantic` models that track the upstream ACP schema (`acp.schema`) -- Async base classes and JSON-RPC plumbing that keep stdio agents tiny -- Process helpers such as `spawn_agent_process` for embedding agents and clients directly in Python -- Batteries-included examples that exercise streaming updates, file I/O, and permission flows -- Optional Gemini CLI bridge (`examples/gemini.py`) for the `gemini --experimental-acp` integration -- Experimental contrib modules (`acp.contrib`) that streamline session state, tool call tracking, and permission prompts +> Releases track the upstream ACP schema; contributions that tighten coverage or tooling are always welcome. ## Install ```bash pip install agent-client-protocol -# or with uv +# or uv add agent-client-protocol ``` -## Quickstart - -1. Install the package and point your ACP-capable client at the provided echo agent: - ```bash - pip install agent-client-protocol - python examples/echo_agent.py - ``` -2. Wire it into your client (e.g. Zed → Agents panel) so stdio is connected; the SDK handles JSON-RPC framing and lifecycle messages. - -Prefer a step-by-step walkthrough? Read the [Quickstart guide](docs/quickstart.md) or the hosted docs: https://agentclientprotocol.github.io/python-sdk/. - -### Launching from Python - -Embed the agent inside another Python process without spawning your own pipes: - -```python -import asyncio -import sys -from pathlib import Path - -from acp import spawn_agent_process, text_block -from acp.schema import InitializeRequest, NewSessionRequest, PromptRequest - - -async def main() -> None: - agent_script = Path("examples/echo_agent.py") - async with spawn_agent_process(lambda _agent: YourClient(), sys.executable, str(agent_script)) as (conn, _proc): - await conn.initialize(InitializeRequest(protocolVersion=1)) - session = await conn.newSession(NewSessionRequest(cwd=str(agent_script.parent), mcpServers=[])) - await conn.prompt( - PromptRequest( - sessionId=session.sessionId, - prompt=[text_block("Hello!")], - ) - ) - - -asyncio.run(main()) -``` - -`spawn_client_process` mirrors this pattern for the inverse direction. - -### Minimal agent sketch - -```python -import asyncio - -from acp import ( - Agent, - AgentSideConnection, - InitializeRequest, - InitializeResponse, - NewSessionRequest, - NewSessionResponse, - PromptRequest, - PromptResponse, - session_notification, - stdio_streams, - text_block, - update_agent_message, -) - - -class EchoAgent(Agent): - def __init__(self, conn): - self._conn = conn - - async def initialize(self, params: InitializeRequest) -> InitializeResponse: - return InitializeResponse(protocolVersion=params.protocolVersion) - - async def newSession(self, params: NewSessionRequest) -> NewSessionResponse: - return NewSessionResponse(sessionId="sess-1") - - async def prompt(self, params: PromptRequest) -> PromptResponse: - for block in params.prompt: - text = block.get("text", "") if isinstance(block, dict) else getattr(block, "text", "") - await self._conn.sessionUpdate( - session_notification( - params.sessionId, - update_agent_message(text_block(text)), - ) - ) - return PromptResponse(stopReason="end_turn") - - -async def main() -> None: - reader, writer = await stdio_streams() - AgentSideConnection(lambda conn: EchoAgent(conn), writer, reader) - await asyncio.Event().wait() - - -if __name__ == "__main__": - asyncio.run(main()) -``` - -Full example with streaming and lifecycle hooks lives in [examples/echo_agent.py](examples/echo_agent.py). - -## Examples - -- `examples/echo_agent.py`: the canonical streaming agent with lifecycle hooks -- `examples/client.py`: interactive console client that can launch any ACP agent via stdio -- `examples/agent.py`: richer agent showcasing initialization, authentication, and chunked updates -- `examples/duet.py`: launches both example agent and client using `spawn_agent_process` -- `examples/gemini.py`: connects to the Gemini CLI in `--experimental-acp` mode, with optional auto-approval and sandbox flags - -## Helper APIs - -Use `acp.helpers` to build protocol payloads without manually shaping dictionaries: - -```python -from acp import ( - start_read_tool_call, - text_block, - tool_content, - update_available_commands, - update_tool_call, -) - -start = start_read_tool_call("call-1", "Inspect config", path="config.toml") -commands = update_available_commands([]) -update = update_tool_call("call-1", status="completed", content=[tool_content(text_block("Done."))]) -``` - -Helpers cover content blocks (`text_block`, `resource_link_block`), embedded resources, tool calls (`start_edit_tool_call`, `update_tool_call`), and session updates (`update_agent_message_text`, `update_available_commands`, `update_current_mode`, `session_notification`). +## At a glance -## Contrib helpers +- **Spec parity:** Generated Pydantic models in `acp.schema` track every ACP release so payloads stay valid. +- **Runtime ergonomics:** Async base classes, stdio JSON-RPC plumbing, and lifecycle helpers keep custom agents tiny. +- **Examples ready:** Streaming, permissions, Gemini bridge, and duet demos live under `examples/`. +- **Helper builders:** `acp.helpers` mirrors the Go/TS SDK APIs for content blocks, tool calls, and session updates. +- **Contrib utilities:** Session accumulators, tool call trackers, and permission brokers share patterns from real deployments. -The experimental `acp.contrib` package captures patterns from reference integrations: +## Who benefits -- `SessionAccumulator` (`acp.contrib.session_state`) merges `SessionNotification` streams into immutable snapshots for UI rendering. -- `ToolCallTracker` (`acp.contrib.tool_calls`) generates consistent tool call starts/updates and buffers streamed content. -- `PermissionBroker` (`acp.contrib.permissions`) wraps permission requests with sensible default option sets. +- Agent authors who need typed models, helper builders, and event-stream ergonomics for ACP-compatible assistants. +- Client integrators embedding ACP parties inside Python applications or wrapping existing CLIs via stdio. +- Tooling teams experimenting with permission flows, streaming UX, or Gemini bridges without re-implementing transports. +See real adopters like kimi-cli in the [Use Cases list](https://agentclientprotocol.github.io/python-sdk/use-cases/). -Read more in [docs/contrib.md](docs/contrib.md). +## How to get started -## Documentation +- Follow the [Quickstart guide](https://agentclientprotocol.github.io/python-sdk/quickstart/) for installation, echo-agent validation, editor wiring (e.g. Zed), and programmatic launch recipes. +- Browse the [example gallery](https://github.com/agentclientprotocol/python-sdk/tree/main/examples) to see progressively richer integrations you can copy or extend. +- Skim the [docs hub](https://agentclientprotocol.github.io/python-sdk/) for focused references on contrib helpers, releasing, and transport details. -- Project docs (MkDocs): https://agentclientprotocol.github.io/python-sdk/ -- Local sources: `docs/` - - [Quickstart](docs/quickstart.md) - - [Contrib helpers](docs/contrib.md) - - [Releasing](docs/releasing.md) +## Quick links -## Gemini CLI bridge +| Need | Link | +| --- | --- | +| Docs hub | https://agentclientprotocol.github.io/python-sdk/ | +| Quickstart | https://agentclientprotocol.github.io/python-sdk/quickstart/ | +| Use cases | https://agentclientprotocol.github.io/python-sdk/use-cases/ | +| Contrib helpers | https://agentclientprotocol.github.io/python-sdk/experimental-contrib/ | +| Releasing workflow | https://agentclientprotocol.github.io/python-sdk/releasing/ | +| Examples | https://github.com/agentclientprotocol/python-sdk/tree/main/examples | +| Tests | https://github.com/agentclientprotocol/python-sdk/tree/main/tests | +| PyPI | https://pypi.org/project/agent-client-protocol/ | -Want to exercise the `gemini` CLI over ACP? The repository includes a Python replica of the Go SDK's REPL: +## Project layout -```bash -python examples/gemini.py --yolo # auto-approve permissions -python examples/gemini.py --sandbox --model gemini-2.5-pro -``` +- `src/acp/`: runtime package (agents, clients, transports, helpers, schema bindings, contrib utilities) +- `schema/`: upstream JSON schema sources (regenerate via `make gen-all`) +- `docs/`: MkDocs content backing the published documentation +- `examples/`: runnable scripts covering stdio orchestration patterns +- `tests/`: pytest suite with golden fixtures and optional Gemini coverage -Defaults assume the CLI is discoverable via `PATH`; override with `--gemini` or `ACP_GEMINI_BIN=/path/to/gemini`. +## Developer commands -The smoke test (`tests/test_gemini_example.py`) is opt-in to avoid false negatives when the CLI is unavailable or lacks credentials. Enable it locally with: +- `make install` provisions the `uv` virtualenv and installs pre-commit hooks. +- `make check` runs Ruff formatting/linting, type analysis, dependency hygiene, and lock verification. +- `make test` executes `pytest` (with doctests) inside the managed environment. +- `ACP_SCHEMA_VERSION= make gen-all` refreshes protocol artifacts when the schema advances. -```bash -ACP_ENABLE_GEMINI_TESTS=1 ACP_GEMINI_BIN=/path/to/gemini uv run python -m pytest tests/test_gemini_example.py -``` - -The test gracefully skips when authentication prompts (e.g. missing `GOOGLE_CLOUD_PROJECT`) block the interaction. - -## Development workflow +Keep docs and examples current whenever you ship public API or transport changes, and prefer Conventional Commits (`feat:`, `fix:`, etc.) when submitting patches. -```bash -make install # create uv virtualenv and install hooks -ACP_SCHEMA_VERSION= make gen-all # refresh generated schema bindings -make check # lint, types, dependency analysis -make test # run pytest + doctests -``` +## Community & support -After local changes, consider updating docs/examples if the public API surface shifts. +- File issues or feature requests at https://github.com/agentclientprotocol/python-sdk. +- Discuss ideas or get help via GitHub Discussions: https://github.com/agentclientprotocol/python-sdk/discussions. +- Join the broader ACP conversations at https://agentclientprotocol.com/, the Zed community channels, or the community Zulip: https://agentclientprotocol.zulipchat.com/. +- Shared learnings, integrations, or third-party transports are welcome additions to the documentation—open a PR! diff --git a/docs/contrib.md b/docs/contrib.md index 63be6a1..a024f43 100644 --- a/docs/contrib.md +++ b/docs/contrib.md @@ -1,40 +1,39 @@ # Experimental Contrib Modules -> The helpers under `acp.contrib` capture patterns we observed in reference integrations such as Toad and kimi-cli. Every API here is experimental and may change without notice. +The helpers under `acp.contrib` package recurring patterns we saw in integrations such as Toad, kimi-cli, and Gemini. Keep in mind they are experimental—APIs can still shift as we learn. Use this page as a menu: -## SessionAccumulator +- **`session_state.SessionAccumulator`** — build a canonical, immutable snapshot of every session update so UIs can render tool calls and plans without re-implementing state machines. +- **`tool_calls.ToolCallTracker` + `permissions.PermissionBroker`** — coordinate streamed tool call updates and permission prompts from one place. -Module: `acp.contrib.session_state` +## SessionAccumulator (`acp.contrib.session_state`) -UI surfaces like Toad need a live, merged view of the latest tool calls, plan entries, and message stream. The core SDK only emits raw `SessionNotification` payloads, so applications usually end up writing their own state layer. `SessionAccumulator` offers that cache out of the box. +**Use it when:** you need a live, merged view of `SessionNotification` events (e.g. tool calls, plan entries, user/agent messages) to drive UI widgets. -Capabilities: +**Key capabilities** -- `SessionAccumulator.apply(notification)` merges `tool_call` and `tool_call_update` events, backfilling a missing start message when necessary. -- Each call to `snapshot()` returns an immutable `SessionSnapshot` (Pydantic model) containing the active plan, current mode ID, available commands, and historical user/agent/thought chunks. -- `subscribe(callback)` wires a lightweight observer that receives every new snapshot, making it easy to refresh UI widgets. -- Automatic reset when a different session ID arrives (configurable via `auto_reset_on_session_change`). +- `SessionAccumulator.apply(notification)` reconciles `tool_call` and `tool_call_update` payloads, even if the start event arrives late. +- `snapshot()` returns an immutable `SessionSnapshot` Pydantic model containing the plan, current mode, commands, and ordered message history. +- `subscribe(callback)` lets you push snapshots into stores or UI components whenever state changes. +- Automatic reset on session-change (toggle with `auto_reset_on_session_change`). -> Integration tip: create one accumulator per UI controller. Feed every `SessionNotification` through it, then render from `snapshot.tool_calls` or `snapshot.user_messages` instead of mutating state manually. +> Tip: Create one accumulator per UI controller. Feed every raw `SessionNotification` into it and render from `snapshot.tool_calls` / `snapshot.user_messages` instead of mutating state manually. -## ToolCallTracker & PermissionBroker +## ToolCallTracker & PermissionBroker (`acp.contrib.tool_calls`, `acp.contrib.permissions`) -Modules: `acp.contrib.tool_calls` and `acp.contrib.permissions` +**Use them when:** your agent runtime synthesises tool call IDs, streams arguments, and prompts the user for approval. The helpers centralise the bookkeeping so you don’t juggle raw Pydantic models. -Agent-side runtimes (for example kimi-cli) are responsible for synthesising tool call IDs, streaming argument fragments, and formatting permission prompts. Managing bare Pydantic models quickly devolves into boilerplate; these helpers centralise the bookkeeping. +- `ToolCallTracker.start()/progress()/append_stream_text()` emits canonical `ToolCallStart` / `ToolCallProgress` updates and keeps an in-memory view via `view()` or `tool_call_model()`. +- `PermissionBroker.request_for()` wraps `requestPermission` RPCs. It reuses tracker state (or a provided `ToolCall`), lets you append extra content, and defaults to Approve / Approve for session / Reject options. +- `default_permission_options()` exposes that canonical option triple if you need to customise it. -- `ToolCallTracker.start()/progress()/append_stream_text()` manages tool call state and emits canonical `ToolCallStart` / `ToolCallProgress` messages. The tracker also exposes `view()` (immutable `TrackedToolCallView`) and `tool_call_model()` for logging or permission prompts. -- `PermissionBroker.request_for()` wraps `requestPermission` RPCs. It reuses the tracker’s state (or an explicit `ToolCall`), applies optional extra content, and defaults to a standard Approve / Approve for session / Reject option set. -- `default_permission_options()` exposes that canonical option triple so applications can customise or extend it. - -> Integration tip: keep a single tracker alongside your agent loop. Emit tool call notifications through it, and hand the tracker to `PermissionBroker` so permission prompts stay in sync with the latest call state. +> Tip: Keep one tracker near the agent event loop. Emit notifications through it and share the tracker with `PermissionBroker` so permission prompts always match the latest tool call state. ## Design Guardrails To stay aligned with the ACP schema, the contrib layer follows a few rules: -- Protocol types continue to live in `acp.schema`. Contrib code always copies them via `.model_copy(deep=True)` to avoid mutating shared instances. -- Helpers are opt-in; the core package never imports them implicitly and imposes no UI or agent framework assumptions. -- Implementations focus on the common pain points (tool call aggregation, permission requests) while leaving business-specific policy to the application. +- Schema data classes continue to live in `acp.schema`. Contrib helpers clone them with `.model_copy(deep=True)` before mutation. +- The core runtime never imports contrib modules implicitly—you opt in when they help. +- Helpers focus on painful bookkeeping (tool call aggregation, permission UX) and leave product-specific policy to your application. -Try the contrib modules in your agent or client, and open an issue/PR with feedback so we can decide which pieces should graduate into the stable surface. +Try the contrib modules, then open an issue or PR with feedback so we know which APIs should graduate into the stable surface. diff --git a/docs/index.md b/docs/index.md index 5a16958..4f70105 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,52 +1,63 @@ - + Agent Client Protocol # Agent Client Protocol SDK (Python) -Welcome to the Python SDK for the Agent Client Protocol (ACP). The package ships ready-to-use transports, typed protocol models, and examples that stream messages to ACP-aware clients such as Zed. +Ship ACP-compatible agents and clients in Python without rebuilding JSON-RPC transports or schema models. This SDK mirrors each ACP release so your integrations stay interoperable with editors, CLIs, and hosted clients. -## What you get +## Install & verify -- Pydantic models generated from the upstream ACP schema (`acp.schema`) -- Async agent/client wrappers with JSON-RPC task supervision built in -- Process helpers (`spawn_agent_process`, `spawn_client_process`) for embedding ACP nodes inside Python applications -- Helper APIs in `acp.helpers` that mirror the Go/TS SDK builders for content blocks, tool calls, and session updates. They instantiate the generated Pydantic types for you, so call sites stay concise without sacrificing validation. -- Examples that showcase streaming updates, file operations, permission flows, and even a Gemini CLI bridge (`examples/gemini.py`) +```bash +pip install agent-client-protocol +# or +uv add agent-client-protocol +``` -## Getting started +Next steps live in the [Quickstart](quickstart.md): launch the echo agent, wire it to Zed (or another ACP client), and exercise the programmatic spawn helpers. -1. Install the package: - ```bash - pip install agent-client-protocol - ``` -2. Launch the provided echo agent to verify your setup: - ```bash - python examples/echo_agent.py - ``` -3. Point your ACP-capable client at the running process (for Zed, configure an Agent Server entry). The SDK takes care of JSON-RPC framing and lifecycle transitions. +## ACP at a glance -Prefer a guided tour? Head to the [Quickstart](quickstart.md) for terminal, editor, and programmatic launch walkthroughs. +- ACP is the stdio protocol that lets “clients” (editors, shells, CLIs) orchestrate AI “agents.” +- Sessions exchange structured payloads (`session/update`, permission prompts, tool calls) defined in the upstream schema. +- Matching the schema version keeps your Python integrations compatible with tools such as Zed, Gemini CLI, or kimi-cli. -## Gemini CLI bridge +## SDK building blocks -If you have access to the Gemini CLI (`gemini --experimental-acp`), run: +- `acp.schema`: generated Pydantic models that validate every payload against the canonical specification. +- `acp.agent` / `acp.client`: async base classes, JSON-RPC supervision, and lifecycle orchestration. +- `acp.helpers`: builders for content blocks, tool calls, permissions, and notifications. +- `acp.contrib`: experimental utilities (session accumulators, permission brokers, tool call trackers) harvested from production deployments. +- `examples/`: runnable agents, clients, duet demos, and the Gemini CLI bridge. -```bash -python examples/gemini.py --yolo -``` +## Quick links + +| Need | Link | +| --- | --- | +| Quickstart walkthrough | [quickstart.md](quickstart.md) | +| Real-world adopters | [use-cases.md](use-cases.md) | +| Contrib helpers | [contrib.md](contrib.md) | +| Releasing workflow | [releasing.md](releasing.md) | +| Example scripts | [github.com/agentclientprotocol/python-sdk/tree/main/examples](https://github.com/agentclientprotocol/python-sdk/tree/main/examples) | + +## Choose a path -Flags mirror the Go SDK example: +- **Just exploring?** Skim [use-cases.md](use-cases.md) to see how kimi-cli, agent-client-kernel, and others use the SDK. +- **Building agents?** Copy `examples/echo_agent.py` or `examples/agent.py`, then layer in `acp.helpers` for tool calls and permissions. +- **Embedding clients?** Start with `examples/client.py` or the `spawn_agent_process` / `spawn_client_process` helpers in the [Quickstart](quickstart.md#programmatic-launch). -- `--gemini /path/to/cli` or `ACP_GEMINI_BIN` to override discovery -- `--model`, `--sandbox`, `--debug` forwarded verbatim -- `--yolo` auto-approves permission prompts with sensible defaults +## Reference material -An opt-in smoke test lives at `tests/test_gemini_example.py`. Enable it with `ACP_ENABLE_GEMINI_TESTS=1` (and optionally `ACP_GEMINI_TEST_ARGS`) when the CLI is authenticated; otherwise the test stays skipped. +- [Quickstart](quickstart.md) — installation, editor wiring, and programmatic launch walkthroughs. +- [Use Cases](use-cases.md) — real adopters with succinct descriptions of what they build. +- [Experimental Contrib](contrib.md) — deep dives on the `acp.contrib` utilities. +- [Releasing](releasing.md) — schema upgrade process, versioning policy, and publishing checklist. -## Documentation map +Need API-level details? Browse the source in `src/acp/` or generate docs with `mkdocstrings`. -- [Quickstart](quickstart.md): install, run, and embed the echo agent, plus next steps for extending it -- [Releasing](releasing.md): schema upgrade workflow, version bumps, and publishing checklist +## Feedback & support -Source code lives under `src/acp/`, while tests and additional examples are available in `tests/` and `examples/`. If you plan to contribute, see the repository README for the development workflow. +- Open issues or discussions on GitHub for bugs, feature requests, or integration help. +- Join [GitHub Discussions](https://github.com/agentclientprotocol/python-sdk/discussions) to swap ideas. +- Chat with the community on [agentclientprotocol.zulipchat.com](https://agentclientprotocol.zulipchat.com/). +- Follow ACP roadmap updates at [agentclientprotocol.com](https://agentclientprotocol.com/). diff --git a/docs/quickstart.md b/docs/quickstart.md index 7c9bca7..3a54147 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -1,13 +1,26 @@ # Quickstart -This guide gets you from a clean environment to streaming ACP messages from a Python agent. +Spin up a working ACP agent/client loop in minutes. Keep this page beside the terminal and check off each section as you go. Want inspiration? Hop to the [Use Cases](use-cases.md) list to see how teams like kimi-cli or Zed apply the SDK in production. -## Prerequisites +## Quick checklist -- Python 3.10-3.14 and either `pip` or `uv` -- An ACP-capable client such as Zed (optional but recommended for testing) +| Goal | Command / Link | +| --- | --- | +| Install the SDK | `pip install agent-client-protocol` or `uv add agent-client-protocol` | +| Run the echo agent | `python examples/echo_agent.py` | +| Point Zed (or another client) at it | Update `settings.json` as shown below | +| Programmatically drive an agent | Copy the `spawn_agent_process` example | +| Run tests before hacking further | `make check && make test` | -## 1. Install the SDK +## Before you begin + +- Python 3.10–3.14 with `pip` or `uv` +- An ACP-capable client such as Zed (recommended for validation) +- Optional: the Gemini CLI (`gemini --experimental-acp`) for the bridge example + +## Step 1 — Install the SDK + +_Install the library from PyPI or add it to your uv workspace._ ```bash pip install agent-client-protocol @@ -15,17 +28,19 @@ pip install agent-client-protocol uv add agent-client-protocol ``` -## 2. Launch the Echo agent (terminal) +## Step 2 — Launch the Echo agent -Start the ready-made echo example — it streams text blocks back to any ACP client: +_Run the provided streaming agent so clients have something to talk to._ + +Start the ready-made echo example; it streams text blocks back to any ACP client. Leave it running in a terminal: ```bash python examples/echo_agent.py ``` -Leave this process running while you connect from an editor or another program. +## Step 3 — Connect from an ACP-aware client -## 3. Connect from an editor +_Point a client at the script and confirm you can exchange streamed updates._ ### Zed @@ -52,6 +67,8 @@ Any ACP client that communicates over stdio can spawn the same script; no additi ### Programmatic launch +Prefer to drive agents directly from Python? The `spawn_agent_process` helper wires stdio and lifecycle management for you: + ```python import asyncio import sys @@ -87,7 +104,9 @@ asyncio.run(main()) `spawn_agent_process` manages the child process, wires its stdio into ACP framing, and closes everything when the block exits. The mirror helper `spawn_client_process` lets you drive an ACP client from Python as well. -## 4. Extend the agent +## Step 4 — Extend the agent + +_Swap the echo demo for your own `Agent` subclass._ Create your own agent by subclassing `acp.Agent`. The pattern mirrors the echo example: @@ -123,7 +142,9 @@ finish_update = update_tool_call( Each helper wraps the generated Pydantic models in `acp.schema`, so the right discriminator fields (`type`, `sessionUpdate`, and friends) are always populated. That keeps examples readable while maintaining the same validation guarantees as constructing the models directly. Golden fixtures in `tests/test_golden.py` ensure the helpers stay in sync with future schema revisions. -## 5. Optional: Talk to the Gemini CLI +## Optional — Talk to the Gemini CLI + +_Have the Gemini CLI installed? Run the bridge to exercise permission flows._ If you have the Gemini CLI installed and authenticated: @@ -139,3 +160,10 @@ Environment helpers: - `ACP_ENABLE_GEMINI_TESTS=1` — opt-in toggle for `tests/test_gemini_example.py` Authentication hiccups (e.g. missing `GOOGLE_CLOUD_PROJECT`) are surfaced but treated as skips during testing so the suite stays green on machines without credentials. + +## Next steps + +- Compare what you built with the real integrations listed on the [Use Cases](use-cases.md) page. +- Explore `docs/contrib.md` for higher-level utilities like session accumulators and permission brokers. +- Run `make check` / `make test` before committing changes, and regenerate schema artifacts with `make gen-all` when ACP versions advance. +- Need help? Start a thread in [GitHub Discussions](https://github.com/agentclientprotocol/python-sdk/discussions) or chat with other ACP developers at [agentclientprotocol.zulipchat.com](https://agentclientprotocol.zulipchat.com/). diff --git a/docs/releasing.md b/docs/releasing.md index 3eac2de..6b3ff65 100644 --- a/docs/releasing.md +++ b/docs/releasing.md @@ -1,57 +1,45 @@ # Releasing -This project tracks the ACP schema tags published by -[`agentclientprotocol/agent-client-protocol`](https://github.com/agentclientprotocol/agent-client-protocol). -Every release should line up with one of those tags so that the generated `acp.schema` module, examples, and package -version remain consistent. - -## Preparation - -Pick the target schema tag (for example `v0.4.5`) and regenerate the protocol bindings: - -```bash -ACP_SCHEMA_VERSION=v0.4.5 make gen-all -``` - -This downloads the upstream schema package and rewrites `schema/` plus the generated `src/acp/schema.py`. - -Bump the project version in `pyproject.toml`, updating `uv.lock` if dependencies changed. - -Run the standard checks: - -```bash -make check -make test -``` - -- `make check` covers Ruff formatting/linting, static analysis, and dependency hygiene. -- `make test` executes pytest (including doctests). - -Refresh documentation and examples (for instance the Gemini walkthrough) so they match the new schema behaviour. - -## Commit & Merge - -1. Make sure the diff only includes the expected artifacts: regenerated schema sources, `src/acp/schema.py`, version bumps, and doc updates. -2. Commit with a Conventional Commit message (for example `release: v0.4.5`) and note in the PR: - - The ACP schema tag you targeted - - Results from `make check` / `make test` - - Any behavioural or API changes worth highlighting -3. Merge once the review is approved. +Every package release tracks an upstream ACP schema tag from [`agentclientprotocol/agent-client-protocol`](https://github.com/agentclientprotocol/agent-client-protocol). Follow this checklist to stay in lockstep. + +## Prep checklist + +1. **Choose the schema tag** (e.g. `v0.4.5`) and regenerate artifacts: + ```bash + ACP_SCHEMA_VERSION=v0.4.5 make gen-all + ``` + This refreshes `schema/` and the generated `src/acp/schema.py`. +2. **Bump the SDK version** in `pyproject.toml` (and regenerate `uv.lock` if deps moved). +3. **Run the standard gates:** + ```bash + make check # Ruff format/lint, type analysis, dep hygiene + make test # pytest + doctests + ``` +4. **Refresh docs + examples** so user-facing flows (e.g. Gemini bridge) reflect behaviour in the new schema. + +## Commit & review + +- Keep the diff tight: regenerated schema files, version bumps, doc updates, and any required fixture refresh (goldens, RPC tests, etc.). +- Use a Conventional Commit such as `release: v0.4.5`. +- In the PR description, capture: + - The ACP schema tag you targeted. + - Output from `make check` / `make test` (and optional Gemini tests if you ran them). + - Behavioural or API highlights that reviewers should focus on. ## Publish via GitHub Release -Publishing is automated through `on-release-main.yml`. After the release PR merges to `main`: +Releases are automated by `on-release-main.yml` once the PR lands on `main`. -1. Draft a GitHub Release for the new tag (e.g. `v0.4.5`). If the tag is missing, the release UI will create it. -2. Once published, the workflow will: - - Write the tag back into `pyproject.toml` to keep the package version aligned - - Build and publish to PyPI via `uv publish` (using the `PYPI_TOKEN` secret) - - Deploy updated documentation with `mkdocs gh-deploy` +1. Draft a GitHub Release for the new tag (the UI creates the tag if missing). +2. Publishing the release triggers the workflow, which: + - Syncs the tag back into `pyproject.toml`. + - Builds and uploads to PyPI via `uv publish` using `PYPI_TOKEN`. + - Deploys updated docs with `mkdocs gh-deploy`. -No local `uv build`/`uv publish` runs are required—focus on providing a complete release summary (highlights, compatibility notes, etc.). +No local build/publish steps are needed—just provide a clear release summary (highlights, compatibility notes, migration tips). -## Additional Notes +## Extra tips -- Breaking schema updates often require refreshing golden fixtures (`tests/test_golden.py`), end-to-end cases such as `tests/test_rpc.py`, and any affected examples. -- Use `make clean` to remove generated artifacts if you need a fresh baseline before re-running `make gen-all`. -- Run optional checks like the Gemini smoke test (`ACP_ENABLE_GEMINI_TESTS=1`) whenever the environment is available to catch regressions before publishing. +- Breaking schema bumps often mean updating `tests/test_golden.py`, `tests/test_rpc.py`, and any examples touched by new fields. +- Use `make clean` if you need a fresh slate before re-running `make gen-all`. +- When available, run the Gemini smoke test (`ACP_ENABLE_GEMINI_TESTS=1`, set `ACP_GEMINI_BIN`) to catch regressions early. diff --git a/docs/use-cases.md b/docs/use-cases.md new file mode 100644 index 0000000..cc55854 --- /dev/null +++ b/docs/use-cases.md @@ -0,0 +1,26 @@ +# Use Cases + +This page mirrors the quick-read style of the README/index: skim the tables, copy links, and see how others apply the SDK. For the protocol overview itself, visit the official [agent](https://agentclientprotocol.com/overview/agents) and [client](https://agentclientprotocol.com/overview/clients) guides. + +## Agents + +| Project | What it showcases | +| --- | --- | +| [MoonshotAI/kimi-cli](https://github.com/MoonshotAI/kimi-cli) | A CLI-first ACP+MCP agent that helps with software dev and terminal workflows. Highlights streaming updates, permission prompts, and tool call UX. | + +## Clients + +| Project | What it showcases | +| --- | --- | +| [jimwhite/agent-client-kernel](https://github.com/jimwhite/agent-client-kernel) | A Jupyter kernel that speaks ACP so notebooks can chat with external agents. Great reference if you’re embedding ACP in notebook tooling. | +| [OhadRubin/simple-acp-client](https://github.com/OhadRubin/simple-acp-client) | A Claude Agent SDK–style Python client that wraps ACP executables with a friendly API. Use it as a starting point for bespoke clients. | + +## Add your integration + +Shipping something with this SDK? Tell us! + +- Open an issue or PR with a short blurb and link. +- Start a thread in [GitHub Discussions](https://github.com/agentclientprotocol/python-sdk/discussions). +- Drop a note in [agentclientprotocol.zulipchat.com](https://agentclientprotocol.zulipchat.com/). + +We’ll keep this list current so newcomers can see what’s possible. diff --git a/mkdocs.yml b/mkdocs.yml index 05cfdba..0464ad0 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -10,6 +10,7 @@ copyright: Maintained by psiace. nav: - Home: index.md - Quick Start: quickstart.md + - Use Cases: use-cases.md - Experimental Contrib: contrib.md - Releasing: releasing.md plugins: diff --git a/src/acp/py.typed b/src/acp/py.typed new file mode 100644 index 0000000..73db90b --- /dev/null +++ b/src/acp/py.typed @@ -0,0 +1 @@ +# Marker file for PEP 561 to indicate the package provides type hints.