pi-agent-python-sdk 0.2.1__tar.gz → 0.2.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (19) hide show
  1. {pi_agent_python_sdk-0.2.1 → pi_agent_python_sdk-0.2.2}/CHANGELOG.md +6 -0
  2. {pi_agent_python_sdk-0.2.1 → pi_agent_python_sdk-0.2.2}/PKG-INFO +155 -109
  3. {pi_agent_python_sdk-0.2.1 → pi_agent_python_sdk-0.2.2}/README.md +152 -106
  4. {pi_agent_python_sdk-0.2.1 → pi_agent_python_sdk-0.2.2}/pyproject.toml +3 -3
  5. {pi_agent_python_sdk-0.2.1 → pi_agent_python_sdk-0.2.2}/src/pi_agent/_launch.py +1 -1
  6. {pi_agent_python_sdk-0.2.1 → pi_agent_python_sdk-0.2.2}/src/pi_agent/types.py +1 -1
  7. {pi_agent_python_sdk-0.2.1 → pi_agent_python_sdk-0.2.2}/.gitignore +0 -0
  8. {pi_agent_python_sdk-0.2.1 → pi_agent_python_sdk-0.2.2}/LICENSE +0 -0
  9. {pi_agent_python_sdk-0.2.1 → pi_agent_python_sdk-0.2.2}/src/pi_agent/__init__.py +0 -0
  10. {pi_agent_python_sdk-0.2.1 → pi_agent_python_sdk-0.2.2}/src/pi_agent/_collections.py +0 -0
  11. {pi_agent_python_sdk-0.2.1 → pi_agent_python_sdk-0.2.2}/src/pi_agent/_events.py +0 -0
  12. {pi_agent_python_sdk-0.2.1 → pi_agent_python_sdk-0.2.2}/src/pi_agent/_observation.py +0 -0
  13. {pi_agent_python_sdk-0.2.1 → pi_agent_python_sdk-0.2.2}/src/pi_agent/_runs.py +0 -0
  14. {pi_agent_python_sdk-0.2.1 → pi_agent_python_sdk-0.2.2}/src/pi_agent/_transport.py +0 -0
  15. {pi_agent_python_sdk-0.2.1 → pi_agent_python_sdk-0.2.2}/src/pi_agent/_usage.py +0 -0
  16. {pi_agent_python_sdk-0.2.1 → pi_agent_python_sdk-0.2.2}/src/pi_agent/client.py +0 -0
  17. {pi_agent_python_sdk-0.2.1 → pi_agent_python_sdk-0.2.2}/src/pi_agent/errors.py +0 -0
  18. {pi_agent_python_sdk-0.2.1 → pi_agent_python_sdk-0.2.2}/src/pi_agent/py.typed +0 -0
  19. {pi_agent_python_sdk-0.2.1 → pi_agent_python_sdk-0.2.2}/src/pi_agent/sync.py +0 -0
@@ -2,6 +2,12 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 0.2.2
6
+
7
+ ### Changed
8
+
9
+ - Update the tested Pi runtime to 0.86.1, retaining 0.85.1 as the minimum.
10
+
5
11
  ## 0.2.1
6
12
 
7
13
  ### Added
@@ -1,11 +1,11 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: pi-agent-python-sdk
3
- Version: 0.2.1
3
+ Version: 0.2.2
4
4
  Summary: Typed async and synchronous Python clients for Pi's agent RPC runtime
5
5
  Project-URL: Homepage, https://github.com/cheenulabs/pi-agent-python-sdk
6
- Project-URL: Documentation, https://github.com/cheenulabs/pi-agent-python-sdk/tree/v0.2.1/docs
6
+ Project-URL: Documentation, https://github.com/cheenulabs/pi-agent-python-sdk/tree/v0.2.2/docs
7
7
  Project-URL: Issues, https://github.com/cheenulabs/pi-agent-python-sdk/issues
8
- Project-URL: Changelog, https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.1/CHANGELOG.md
8
+ Project-URL: Changelog, https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.2/CHANGELOG.md
9
9
  Author: cheenulabs
10
10
  License-Expression: MIT
11
11
  License-File: LICENSE
@@ -23,70 +23,69 @@ Description-Content-Type: text/markdown
23
23
 
24
24
  # Pi Agent Python SDK
25
25
 
26
- [![PyPI](https://badge.fury.io/py/pi-agent-python-sdk.svg)][pypi]
26
+ [![PyPI](https://img.shields.io/pypi/v/pi-agent-python-sdk.svg?style=flat-square)][pypi]
27
27
  [![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-3776AB?style=flat-square)][metadata]
28
28
  [![MIT license](https://img.shields.io/badge/license-MIT-blue?style=flat-square)][license]
29
29
 
30
30
  **Use your installed Pi coding agent as a Python API. Stream responses,
31
31
  continue conversations, and control sessions from Python.**
32
32
 
33
- A community Python SDK for [Pi coding agent](https://github.com/earendil-works/pi).
34
- It starts Pi as a subprocess and exposes the same agent runtime through a typed
35
- Python interface for RPC commands, streaming, and session control.
33
+ [Pi](https://github.com/earendil-works/pi) is an open-source coding agent that
34
+ runs in your terminal. This unofficial community SDK launches the Pi CLI in RPC
35
+ mode and exposes prompts, streaming events, and sessions through typed
36
+ synchronous and asynchronous Python APIs.
36
37
 
37
- > Requires Python **3.11+** and a separate Pi installation. The tested protocol
38
- > baseline is **Pi 0.86.0**; see [compatibility][compatibility] for version and
39
- > platform scope.
40
-
41
- [Quick start](#quick-start) · [Streaming](#streaming) · [Async](#async-usage) ·
42
- [Configuration](#configuration) · [Thinking](#models-and-thinking) ·
43
- [RPC](#rpc-access) · [Documentation](#documentation)
38
+ ```python
39
+ from pi_agent import PiClient
44
40
 
45
- ## Why use this?
41
+ with PiClient() as pi:
42
+ print(pi.run("Explain the current project without changing files.").text)
43
+ ```
46
44
 
47
- If you already use Pi from the terminal, this SDK lets you use the same agent
48
- from Python code. Instead of managing a separate implementation, you can start Pi
49
- in RPC mode and call it as a programmatic API from scripts, apps, services, or
50
- background jobs.
45
+ Requires an installed, configured Pi CLI — see [Prerequisites](#prerequisites).
51
46
 
52
- This is useful when you want to:
47
+ [Prerequisites](#prerequisites) · [Quick start](#quick-start) ·
48
+ [Streaming](#streaming) · [Async](#async-usage) ·
49
+ [Configuration](#configuration) · [Thinking](#models-and-thinking) ·
50
+ [RPC](#rpc-access) · [Documentation](#documentation) ·
51
+ [Troubleshooting](#troubleshooting) · [Support](#support)
53
52
 
54
- - Add Pi-powered coding or reasoning to a Python application.
55
- - Automate project analysis, refactors, or repository workflows.
56
- - Build a service or CLI around Pi without reimplementing the agent runtime.
57
- - Stream text, thinking, tool, and session events in Python.
58
- - Reuse your existing Pi configuration, models, tools, and extensions.
53
+ ## What you can do
59
54
 
60
- The SDK keeps Pi's usual setup and model selection, while exposing a typed Python
61
- interface for prompts, follow-ups, model control, and RPC access. It launches Pi
62
- as a subprocess and communicates over its JSONL protocol; it does not attach to
63
- an already-running interactive Pi terminal session.
55
+ - **Run prompts from Python** — get a final answer, or stream text, thinking, and
56
+ tool events as they happen.
57
+ - **Keep conversations going** — send follow-ups on the same client, or resume,
58
+ fork, and clone sessions.
59
+ - **Control the agent** — switch models, set thinking level, steer mid-run, and
60
+ compact context.
61
+ - **Reuse your Pi setup** — same configuration, tools, and extensions as the CLI,
62
+ with sync or async clients.
64
63
 
65
- ## What you can do
64
+ ## Prerequisites
66
65
 
67
- - **Run and stream:** get a final answer or consume text, thinking, and tool events.
68
- - **Keep a conversation:** send follow-up prompts, resume sessions, fork, or clone.
69
- - **Control Pi:** select models, adjust thinking, steer work, compact context, and
70
- call all 33 RPC commands in the pinned baseline.
71
- - **Integrate with your application:** use sync or async clients, typed results,
72
- raw event dictionaries, and extension UI callbacks.
66
+ | Requirement | Notes |
67
+ | --- | --- |
68
+ | Python **3.11+** | Package metadata requires 3.11 or newer |
69
+ | Node.js **22.19.0+** | Required by Pi 0.86.1 |
70
+ | Pi **0.85.1+** | Minimum accepted version; **0.86.1** is the tested baseline |
71
+ | Model provider | Required; configure with the Pi CLI (see Quick start) |
73
72
 
74
73
  ## Quick start
75
74
 
76
- Install Pi with Node.js **22.19.0 or newer**:
75
+ Install Pi with Node.js **22.19.0 or newer** (pin matches the tested baseline):
77
76
 
78
77
  ```sh
79
- npm install -g @earendil-works/pi-coding-agent@0.86.0
78
+ npm install -g @earendil-works/pi-coding-agent@0.86.1
80
79
  pi --version
81
80
  ```
82
81
 
83
- Run `pi` once to configure your provider and model using Pi's normal setup.
84
- The SDK uses that configuration when it starts Pi.
82
+ Run `pi` once to configure your provider and model. The SDK uses that
83
+ configuration when it starts Pi.
85
84
 
86
85
  Install the Python package from [PyPI][pypi]:
87
86
 
88
87
  ```sh
89
- python -m pip install pi-agent-python-sdk==0.2.1
88
+ python -m pip install pi-agent-python-sdk
90
89
  ```
91
90
 
92
91
  The distribution is named `pi-agent-python-sdk`; import it as
@@ -101,8 +100,8 @@ with PiClient() as pi:
101
100
  ```
102
101
 
103
102
  The context manager starts and closes Pi. `run()` waits for the conversation to
104
- settle, including retries and queued follow-ups. The result includes finalized
105
- messages, session identity, elapsed time, and observed assistant usage.
103
+ settle. The result includes finalized messages, session identity, elapsed time,
104
+ and observed assistant usage.
106
105
 
107
106
  Continue the conversation with another call on the same client:
108
107
 
@@ -131,9 +130,15 @@ with PiClient() as pi:
131
130
  print(f"\nStop reason: {result.stop_reason}")
132
131
  ```
133
132
 
133
+ <details>
134
+ <summary>Streaming details</summary>
135
+
134
136
  `event.raw` contains the full Pi event, including fields the SDK does not yet
135
- recognize. Keep the stream inside its context: leaving early cleans up unfinished work. See [errors and cancellation][errors] for
136
- handling timeouts and partial results.
137
+ recognize. Keep the stream inside its context: leaving early cleans up unfinished
138
+ work. See [errors and cancellation][errors] for handling timeouts and partial
139
+ results.
140
+
141
+ </details>
137
142
 
138
143
  ## Async usage
139
144
 
@@ -156,8 +161,13 @@ if __name__ == "__main__":
156
161
  asyncio.run(main())
157
162
  ```
158
163
 
159
- Async streaming uses `async with pi.stream(...)`, `async for event in stream`,
160
- and `await stream.result()`. See the [complete streaming example][stream-example].
164
+ <details>
165
+ <summary>Async streaming</summary>
166
+
167
+ Use `async with pi.stream(...)`, `async for event in stream`, and
168
+ `await stream.result()`. See the [complete streaming example][stream-example].
169
+
170
+ </details>
161
171
 
162
172
  ## Configuration
163
173
 
@@ -171,46 +181,70 @@ with PiClient(cwd=".", no_session=True) as pi:
171
181
  ```
172
182
 
173
183
  Leave `no_session` unset to preserve Pi's normal session persistence. Use
174
- `provider=` and `model=` to override Pi's configured model, or `session=` to open
175
- an existing session. See [constructor options][constructor-options]
176
- for environment overrides, executable paths, and deadlines.
184
+ `session=` to open an existing session. For model overrides, see
185
+ [Models and thinking](#models-and-thinking).
186
+
187
+ <details>
188
+ <summary>More configuration</summary>
189
+
190
+ See [constructor options][constructor-options] for environment overrides,
191
+ executable paths, and deadlines.
177
192
 
178
193
  Extensions are installed and configured through Pi. To load your own extension,
179
- pass `extra_args=["--extension", "/absolute/path/to/your-extension.ts"]` to either
180
- client. See [using your own extensions][extensions]
181
- for details and [extension UI][ui-example] for an interactive example.
194
+ pass `extra_args=["--extension", "/absolute/path/to/your-extension.ts"]` to
195
+ either client. See [using your own extensions][extensions] for details and
196
+ [extension UI][ui-example] for an interactive example.
197
+
198
+ </details>
182
199
 
183
200
  ## Models and thinking
184
201
 
185
- The SDK uses Pi's configured model unless you pass `provider=` and `model=`.
186
- Pi determines which thinking levels that model supports; query them before
187
- choosing a level:
202
+ By default the SDK uses whatever model you already configured in the Pi CLI.
203
+ Override it when you construct the client, or switch later on the same client.
204
+ Set the model and thinking level **before** `run()` or `stream()`.
205
+
206
+ Select a model at construction:
207
+
208
+ ```python
209
+ from pi_agent import PiClient
210
+
211
+ with PiClient(provider="openai", model="gpt-5") as pi:
212
+ print(pi.run("Summarise this repo without changing files.").text)
213
+ ```
214
+
215
+ Thinking levels depend on the current model. Query them, set one, then confirm
216
+ what Pi actually applied:
188
217
 
189
218
  ```python
190
219
  from pi_agent import PiClient
191
220
 
192
221
  with PiClient() as pi:
193
222
  levels = pi.get_available_thinking_levels()
194
- print("Supported thinking levels:", levels)
223
+ print("available:", levels)
195
224
  if "high" in levels:
196
225
  pi.set_thinking_level("high")
197
- print("Effective thinking level:", pi.get_state()["thinkingLevel"])
198
-
199
- result = pi.run("Analyse this project's architecture without changing files.")
200
- print(result.text)
226
+ print("effective:", pi.get_state()["thinkingLevel"])
227
+ print(pi.run("Analyse this project's architecture without changing files.").text)
201
228
  ```
202
229
 
203
- Set the model and thinking level before starting `run()` or `stream()`. Pi can
204
- adjust unsupported level requests, so read `get_state()["thinkingLevel"]` for the
205
- effective value. The setting applies to subsequent prompts in the current
206
- session without changing global defaults. With `AsyncPiClient`, await the same
207
- methods. See the [model and thinking commands][thinking-reference] for cycling
208
- levels and other controls.
230
+ Replace the example provider/model ids with ones from your Pi install
231
+ (`pi --list-models` or `get_available_models()`).
232
+
233
+ <details>
234
+ <summary>List models and switch after start</summary>
235
+
236
+ ```python
237
+ from pi_agent import PiClient
209
238
 
210
- The thinking level controls Pi's reasoning setting. Thinking **output** is
211
- separate: when Pi emits it, deltas are available in `event.raw` during streaming
212
- and finalized thinking blocks in `result.messages`. `result.text` contains the
213
- final assistant text, not thinking.
239
+ with PiClient() as pi:
240
+ for model in pi.get_available_models():
241
+ print(model["provider"], model["id"])
242
+ selected = pi.set_model("openai", "gpt-5")
243
+ print("using", selected["provider"], selected["id"])
244
+ print(pi.run("Summarise this repo without changing files.").text)
245
+ ```
246
+
247
+ </details>
214
248
 
215
249
  ## RPC access
216
250
 
@@ -223,7 +257,18 @@ Your Python application
223
257
  Models · tools · extensions · sessions
224
258
  ```
225
259
 
226
- Choose the interface that fits the work:
260
+ Inspect session state without starting a model run:
261
+
262
+ ```python
263
+ from pi_agent import PiClient
264
+
265
+ with PiClient() as pi:
266
+ state = pi.get_state()
267
+ print(state["sessionId"])
268
+ ```
269
+
270
+ <details>
271
+ <summary>Which interface to use</summary>
227
272
 
228
273
  | You need | Use |
229
274
  | --- | --- |
@@ -235,29 +280,20 @@ Choose the interface that fits the work:
235
280
  | A specific Pi operation | `get_state()`, `set_model()`, `fork()`, and other command methods |
236
281
  | A raw command response envelope | `request()` |
237
282
 
238
- For example, inspect session state without starting a model run:
239
-
240
- ```python
241
- from pi_agent import PiClient
242
-
243
- with PiClient() as pi:
244
- state = pi.get_state()
245
- print(state["sessionId"])
246
- ```
247
-
248
283
  Python arguments use `snake_case`; wire dictionaries retain Pi's `camelCase`
249
284
  fields. `prompt()` acknowledges submission, which may be handled entirely by an
250
285
  extension. It does not wait for a completed answer.
251
286
 
252
- Use one client per conversation and wait for each `run()` or stream to finish
253
- before starting the next. After using `prompt()` for your own event handling,
254
- use a fresh client for `run()` or `stream()` so results cannot include delayed
255
- events from earlier work. The SDK launches a new process and cannot attach to an existing
256
- Pi terminal session.
287
+ Each client starts its own Pi subprocess. Use one client per conversation and
288
+ wait for each `run()` or stream to finish before starting the next. After using
289
+ `prompt()` for your own event handling, use a fresh client for `run()` or
290
+ `stream()` so results cannot include delayed events from earlier work.
257
291
 
258
292
  See [RPC structure][rpc] for the protocol mapping and module layout, and
259
293
  the [command reference][commands] for every method.
260
294
 
295
+ </details>
296
+
261
297
  ## Documentation
262
298
 
263
299
  | Guide | Contents |
@@ -268,36 +304,46 @@ the [command reference][commands] for every method.
268
304
  | [RPC structure][rpc] | How the Python client maps to Pi's protocol |
269
305
  | [Compatibility][compatibility] | Runtime versions and platform validation |
270
306
  | [Examples][examples] | Runnable sync, async, streaming, sessions, steering, and UI examples |
271
- | [Release notes][release] | Changes included in 0.2.1 |
307
+ | [Release notes][release] | Changes included in 0.2.2 |
272
308
 
273
309
  Examples use your configured Pi and may make provider calls. Development checks
274
310
  use an isolated local test provider; see [CONTRIBUTING.md][contributing] for
275
311
  setup and validation commands.
276
312
 
277
- Maintainers: [protocol discovery][discovery] ·
278
- [maintenance][maintenance] · [release checklist][releasing].
313
+ ## Troubleshooting
314
+
315
+ | Symptom | What to check |
316
+ | --- | --- |
317
+ | `pi` not found / launch fails | Ensure the Pi CLI is on `PATH`, or pass `executable=` to the client |
318
+ | Version rejected | Upgrade to Pi **0.85.1+**; prefer the tested baseline **0.86.1** |
319
+ | No model / auth errors | Run `pi` once and complete provider setup |
320
+ | Unexpected file or command changes | Review Pi tool/extension settings before automation |
321
+
322
+ ## Support
323
+
324
+ - [Open an issue][issues] for bugs, questions, or compatibility reports.
325
+ - See [CONTRIBUTING.md][contributing] for local setup and pull requests.
326
+ - For security reports, open a [private security advisory][security].
279
327
 
280
328
  ## License
281
329
 
282
330
  [MIT][license]
283
331
 
284
332
  [pypi]: https://pypi.org/project/pi-agent-python-sdk/
285
- [release]: https://github.com/cheenulabs/pi-agent-python-sdk/releases/tag/v0.2.1
286
- [metadata]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.1/pyproject.toml
287
- [license]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.1/LICENSE
288
- [compatibility]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.1/docs/compatibility.md
289
- [errors]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.1/docs/errors.md
290
- [stream-example]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.1/examples/stream.py
291
- [constructor-options]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.1/docs/api.md#constructor-options
292
- [extensions]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.1/docs/usage.md#using-your-own-extensions
293
- [ui-example]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.1/examples/ui.py
294
- [rpc]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.1/docs/rpc.md
295
- [commands]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.1/docs/api.md#all-33-rpc-commands
296
- [thinking-reference]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.1/docs/api.md#models-state-and-compaction
297
- [usage]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.1/docs/usage.md
298
- [api]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.1/docs/api.md
299
- [examples]: https://github.com/cheenulabs/pi-agent-python-sdk/tree/v0.2.1/examples
300
- [contributing]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.1/CONTRIBUTING.md
301
- [discovery]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.1/docs/discovery.md
302
- [maintenance]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.1/docs/maintenance.md
303
- [releasing]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.1/docs/releasing.md
333
+ [release]: https://github.com/cheenulabs/pi-agent-python-sdk/releases/tag/v0.2.2
334
+ [metadata]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.2/pyproject.toml
335
+ [license]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.2/LICENSE
336
+ [compatibility]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.2/docs/compatibility.md
337
+ [errors]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.2/docs/errors.md
338
+ [stream-example]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.2/examples/stream.py
339
+ [constructor-options]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.2/docs/api.md#constructor-options
340
+ [extensions]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.2/docs/usage.md#using-your-own-extensions
341
+ [ui-example]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.2/examples/ui.py
342
+ [rpc]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.2/docs/rpc.md
343
+ [commands]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.2/docs/api.md#all-33-rpc-commands
344
+ [usage]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.2/docs/usage.md
345
+ [api]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.2/docs/api.md
346
+ [examples]: https://github.com/cheenulabs/pi-agent-python-sdk/tree/v0.2.2/examples
347
+ [contributing]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.2/CONTRIBUTING.md
348
+ [issues]: https://github.com/cheenulabs/pi-agent-python-sdk/issues
349
+ [security]: https://github.com/cheenulabs/pi-agent-python-sdk/security/advisories/new
@@ -1,69 +1,68 @@
1
1
  # Pi Agent Python SDK
2
2
 
3
- [![PyPI](https://badge.fury.io/py/pi-agent-python-sdk.svg)][pypi]
3
+ [![PyPI](https://img.shields.io/pypi/v/pi-agent-python-sdk.svg?style=flat-square)][pypi]
4
4
  [![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-3776AB?style=flat-square)][metadata]
5
5
  [![MIT license](https://img.shields.io/badge/license-MIT-blue?style=flat-square)][license]
6
6
 
7
7
  **Use your installed Pi coding agent as a Python API. Stream responses,
8
8
  continue conversations, and control sessions from Python.**
9
9
 
10
- A community Python SDK for [Pi coding agent](https://github.com/earendil-works/pi).
11
- It starts Pi as a subprocess and exposes the same agent runtime through a typed
12
- Python interface for RPC commands, streaming, and session control.
10
+ [Pi](https://github.com/earendil-works/pi) is an open-source coding agent that
11
+ runs in your terminal. This unofficial community SDK launches the Pi CLI in RPC
12
+ mode and exposes prompts, streaming events, and sessions through typed
13
+ synchronous and asynchronous Python APIs.
13
14
 
14
- > Requires Python **3.11+** and a separate Pi installation. The tested protocol
15
- > baseline is **Pi 0.86.0**; see [compatibility][compatibility] for version and
16
- > platform scope.
17
-
18
- [Quick start](#quick-start) · [Streaming](#streaming) · [Async](#async-usage) ·
19
- [Configuration](#configuration) · [Thinking](#models-and-thinking) ·
20
- [RPC](#rpc-access) · [Documentation](#documentation)
15
+ ```python
16
+ from pi_agent import PiClient
21
17
 
22
- ## Why use this?
18
+ with PiClient() as pi:
19
+ print(pi.run("Explain the current project without changing files.").text)
20
+ ```
23
21
 
24
- If you already use Pi from the terminal, this SDK lets you use the same agent
25
- from Python code. Instead of managing a separate implementation, you can start Pi
26
- in RPC mode and call it as a programmatic API from scripts, apps, services, or
27
- background jobs.
22
+ Requires an installed, configured Pi CLI — see [Prerequisites](#prerequisites).
28
23
 
29
- This is useful when you want to:
24
+ [Prerequisites](#prerequisites) · [Quick start](#quick-start) ·
25
+ [Streaming](#streaming) · [Async](#async-usage) ·
26
+ [Configuration](#configuration) · [Thinking](#models-and-thinking) ·
27
+ [RPC](#rpc-access) · [Documentation](#documentation) ·
28
+ [Troubleshooting](#troubleshooting) · [Support](#support)
30
29
 
31
- - Add Pi-powered coding or reasoning to a Python application.
32
- - Automate project analysis, refactors, or repository workflows.
33
- - Build a service or CLI around Pi without reimplementing the agent runtime.
34
- - Stream text, thinking, tool, and session events in Python.
35
- - Reuse your existing Pi configuration, models, tools, and extensions.
30
+ ## What you can do
36
31
 
37
- The SDK keeps Pi's usual setup and model selection, while exposing a typed Python
38
- interface for prompts, follow-ups, model control, and RPC access. It launches Pi
39
- as a subprocess and communicates over its JSONL protocol; it does not attach to
40
- an already-running interactive Pi terminal session.
32
+ - **Run prompts from Python** — get a final answer, or stream text, thinking, and
33
+ tool events as they happen.
34
+ - **Keep conversations going** — send follow-ups on the same client, or resume,
35
+ fork, and clone sessions.
36
+ - **Control the agent** — switch models, set thinking level, steer mid-run, and
37
+ compact context.
38
+ - **Reuse your Pi setup** — same configuration, tools, and extensions as the CLI,
39
+ with sync or async clients.
41
40
 
42
- ## What you can do
41
+ ## Prerequisites
43
42
 
44
- - **Run and stream:** get a final answer or consume text, thinking, and tool events.
45
- - **Keep a conversation:** send follow-up prompts, resume sessions, fork, or clone.
46
- - **Control Pi:** select models, adjust thinking, steer work, compact context, and
47
- call all 33 RPC commands in the pinned baseline.
48
- - **Integrate with your application:** use sync or async clients, typed results,
49
- raw event dictionaries, and extension UI callbacks.
43
+ | Requirement | Notes |
44
+ | --- | --- |
45
+ | Python **3.11+** | Package metadata requires 3.11 or newer |
46
+ | Node.js **22.19.0+** | Required by Pi 0.86.1 |
47
+ | Pi **0.85.1+** | Minimum accepted version; **0.86.1** is the tested baseline |
48
+ | Model provider | Required; configure with the Pi CLI (see Quick start) |
50
49
 
51
50
  ## Quick start
52
51
 
53
- Install Pi with Node.js **22.19.0 or newer**:
52
+ Install Pi with Node.js **22.19.0 or newer** (pin matches the tested baseline):
54
53
 
55
54
  ```sh
56
- npm install -g @earendil-works/pi-coding-agent@0.86.0
55
+ npm install -g @earendil-works/pi-coding-agent@0.86.1
57
56
  pi --version
58
57
  ```
59
58
 
60
- Run `pi` once to configure your provider and model using Pi's normal setup.
61
- The SDK uses that configuration when it starts Pi.
59
+ Run `pi` once to configure your provider and model. The SDK uses that
60
+ configuration when it starts Pi.
62
61
 
63
62
  Install the Python package from [PyPI][pypi]:
64
63
 
65
64
  ```sh
66
- python -m pip install pi-agent-python-sdk==0.2.1
65
+ python -m pip install pi-agent-python-sdk
67
66
  ```
68
67
 
69
68
  The distribution is named `pi-agent-python-sdk`; import it as
@@ -78,8 +77,8 @@ with PiClient() as pi:
78
77
  ```
79
78
 
80
79
  The context manager starts and closes Pi. `run()` waits for the conversation to
81
- settle, including retries and queued follow-ups. The result includes finalized
82
- messages, session identity, elapsed time, and observed assistant usage.
80
+ settle. The result includes finalized messages, session identity, elapsed time,
81
+ and observed assistant usage.
83
82
 
84
83
  Continue the conversation with another call on the same client:
85
84
 
@@ -108,9 +107,15 @@ with PiClient() as pi:
108
107
  print(f"\nStop reason: {result.stop_reason}")
109
108
  ```
110
109
 
110
+ <details>
111
+ <summary>Streaming details</summary>
112
+
111
113
  `event.raw` contains the full Pi event, including fields the SDK does not yet
112
- recognize. Keep the stream inside its context: leaving early cleans up unfinished work. See [errors and cancellation][errors] for
113
- handling timeouts and partial results.
114
+ recognize. Keep the stream inside its context: leaving early cleans up unfinished
115
+ work. See [errors and cancellation][errors] for handling timeouts and partial
116
+ results.
117
+
118
+ </details>
114
119
 
115
120
  ## Async usage
116
121
 
@@ -133,8 +138,13 @@ if __name__ == "__main__":
133
138
  asyncio.run(main())
134
139
  ```
135
140
 
136
- Async streaming uses `async with pi.stream(...)`, `async for event in stream`,
137
- and `await stream.result()`. See the [complete streaming example][stream-example].
141
+ <details>
142
+ <summary>Async streaming</summary>
143
+
144
+ Use `async with pi.stream(...)`, `async for event in stream`, and
145
+ `await stream.result()`. See the [complete streaming example][stream-example].
146
+
147
+ </details>
138
148
 
139
149
  ## Configuration
140
150
 
@@ -148,46 +158,70 @@ with PiClient(cwd=".", no_session=True) as pi:
148
158
  ```
149
159
 
150
160
  Leave `no_session` unset to preserve Pi's normal session persistence. Use
151
- `provider=` and `model=` to override Pi's configured model, or `session=` to open
152
- an existing session. See [constructor options][constructor-options]
153
- for environment overrides, executable paths, and deadlines.
161
+ `session=` to open an existing session. For model overrides, see
162
+ [Models and thinking](#models-and-thinking).
163
+
164
+ <details>
165
+ <summary>More configuration</summary>
166
+
167
+ See [constructor options][constructor-options] for environment overrides,
168
+ executable paths, and deadlines.
154
169
 
155
170
  Extensions are installed and configured through Pi. To load your own extension,
156
- pass `extra_args=["--extension", "/absolute/path/to/your-extension.ts"]` to either
157
- client. See [using your own extensions][extensions]
158
- for details and [extension UI][ui-example] for an interactive example.
171
+ pass `extra_args=["--extension", "/absolute/path/to/your-extension.ts"]` to
172
+ either client. See [using your own extensions][extensions] for details and
173
+ [extension UI][ui-example] for an interactive example.
174
+
175
+ </details>
159
176
 
160
177
  ## Models and thinking
161
178
 
162
- The SDK uses Pi's configured model unless you pass `provider=` and `model=`.
163
- Pi determines which thinking levels that model supports; query them before
164
- choosing a level:
179
+ By default the SDK uses whatever model you already configured in the Pi CLI.
180
+ Override it when you construct the client, or switch later on the same client.
181
+ Set the model and thinking level **before** `run()` or `stream()`.
182
+
183
+ Select a model at construction:
184
+
185
+ ```python
186
+ from pi_agent import PiClient
187
+
188
+ with PiClient(provider="openai", model="gpt-5") as pi:
189
+ print(pi.run("Summarise this repo without changing files.").text)
190
+ ```
191
+
192
+ Thinking levels depend on the current model. Query them, set one, then confirm
193
+ what Pi actually applied:
165
194
 
166
195
  ```python
167
196
  from pi_agent import PiClient
168
197
 
169
198
  with PiClient() as pi:
170
199
  levels = pi.get_available_thinking_levels()
171
- print("Supported thinking levels:", levels)
200
+ print("available:", levels)
172
201
  if "high" in levels:
173
202
  pi.set_thinking_level("high")
174
- print("Effective thinking level:", pi.get_state()["thinkingLevel"])
175
-
176
- result = pi.run("Analyse this project's architecture without changing files.")
177
- print(result.text)
203
+ print("effective:", pi.get_state()["thinkingLevel"])
204
+ print(pi.run("Analyse this project's architecture without changing files.").text)
178
205
  ```
179
206
 
180
- Set the model and thinking level before starting `run()` or `stream()`. Pi can
181
- adjust unsupported level requests, so read `get_state()["thinkingLevel"]` for the
182
- effective value. The setting applies to subsequent prompts in the current
183
- session without changing global defaults. With `AsyncPiClient`, await the same
184
- methods. See the [model and thinking commands][thinking-reference] for cycling
185
- levels and other controls.
207
+ Replace the example provider/model ids with ones from your Pi install
208
+ (`pi --list-models` or `get_available_models()`).
209
+
210
+ <details>
211
+ <summary>List models and switch after start</summary>
212
+
213
+ ```python
214
+ from pi_agent import PiClient
186
215
 
187
- The thinking level controls Pi's reasoning setting. Thinking **output** is
188
- separate: when Pi emits it, deltas are available in `event.raw` during streaming
189
- and finalized thinking blocks in `result.messages`. `result.text` contains the
190
- final assistant text, not thinking.
216
+ with PiClient() as pi:
217
+ for model in pi.get_available_models():
218
+ print(model["provider"], model["id"])
219
+ selected = pi.set_model("openai", "gpt-5")
220
+ print("using", selected["provider"], selected["id"])
221
+ print(pi.run("Summarise this repo without changing files.").text)
222
+ ```
223
+
224
+ </details>
191
225
 
192
226
  ## RPC access
193
227
 
@@ -200,7 +234,18 @@ Your Python application
200
234
  Models · tools · extensions · sessions
201
235
  ```
202
236
 
203
- Choose the interface that fits the work:
237
+ Inspect session state without starting a model run:
238
+
239
+ ```python
240
+ from pi_agent import PiClient
241
+
242
+ with PiClient() as pi:
243
+ state = pi.get_state()
244
+ print(state["sessionId"])
245
+ ```
246
+
247
+ <details>
248
+ <summary>Which interface to use</summary>
204
249
 
205
250
  | You need | Use |
206
251
  | --- | --- |
@@ -212,29 +257,20 @@ Choose the interface that fits the work:
212
257
  | A specific Pi operation | `get_state()`, `set_model()`, `fork()`, and other command methods |
213
258
  | A raw command response envelope | `request()` |
214
259
 
215
- For example, inspect session state without starting a model run:
216
-
217
- ```python
218
- from pi_agent import PiClient
219
-
220
- with PiClient() as pi:
221
- state = pi.get_state()
222
- print(state["sessionId"])
223
- ```
224
-
225
260
  Python arguments use `snake_case`; wire dictionaries retain Pi's `camelCase`
226
261
  fields. `prompt()` acknowledges submission, which may be handled entirely by an
227
262
  extension. It does not wait for a completed answer.
228
263
 
229
- Use one client per conversation and wait for each `run()` or stream to finish
230
- before starting the next. After using `prompt()` for your own event handling,
231
- use a fresh client for `run()` or `stream()` so results cannot include delayed
232
- events from earlier work. The SDK launches a new process and cannot attach to an existing
233
- Pi terminal session.
264
+ Each client starts its own Pi subprocess. Use one client per conversation and
265
+ wait for each `run()` or stream to finish before starting the next. After using
266
+ `prompt()` for your own event handling, use a fresh client for `run()` or
267
+ `stream()` so results cannot include delayed events from earlier work.
234
268
 
235
269
  See [RPC structure][rpc] for the protocol mapping and module layout, and
236
270
  the [command reference][commands] for every method.
237
271
 
272
+ </details>
273
+
238
274
  ## Documentation
239
275
 
240
276
  | Guide | Contents |
@@ -245,36 +281,46 @@ the [command reference][commands] for every method.
245
281
  | [RPC structure][rpc] | How the Python client maps to Pi's protocol |
246
282
  | [Compatibility][compatibility] | Runtime versions and platform validation |
247
283
  | [Examples][examples] | Runnable sync, async, streaming, sessions, steering, and UI examples |
248
- | [Release notes][release] | Changes included in 0.2.1 |
284
+ | [Release notes][release] | Changes included in 0.2.2 |
249
285
 
250
286
  Examples use your configured Pi and may make provider calls. Development checks
251
287
  use an isolated local test provider; see [CONTRIBUTING.md][contributing] for
252
288
  setup and validation commands.
253
289
 
254
- Maintainers: [protocol discovery][discovery] ·
255
- [maintenance][maintenance] · [release checklist][releasing].
290
+ ## Troubleshooting
291
+
292
+ | Symptom | What to check |
293
+ | --- | --- |
294
+ | `pi` not found / launch fails | Ensure the Pi CLI is on `PATH`, or pass `executable=` to the client |
295
+ | Version rejected | Upgrade to Pi **0.85.1+**; prefer the tested baseline **0.86.1** |
296
+ | No model / auth errors | Run `pi` once and complete provider setup |
297
+ | Unexpected file or command changes | Review Pi tool/extension settings before automation |
298
+
299
+ ## Support
300
+
301
+ - [Open an issue][issues] for bugs, questions, or compatibility reports.
302
+ - See [CONTRIBUTING.md][contributing] for local setup and pull requests.
303
+ - For security reports, open a [private security advisory][security].
256
304
 
257
305
  ## License
258
306
 
259
307
  [MIT][license]
260
308
 
261
309
  [pypi]: https://pypi.org/project/pi-agent-python-sdk/
262
- [release]: https://github.com/cheenulabs/pi-agent-python-sdk/releases/tag/v0.2.1
263
- [metadata]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.1/pyproject.toml
264
- [license]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.1/LICENSE
265
- [compatibility]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.1/docs/compatibility.md
266
- [errors]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.1/docs/errors.md
267
- [stream-example]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.1/examples/stream.py
268
- [constructor-options]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.1/docs/api.md#constructor-options
269
- [extensions]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.1/docs/usage.md#using-your-own-extensions
270
- [ui-example]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.1/examples/ui.py
271
- [rpc]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.1/docs/rpc.md
272
- [commands]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.1/docs/api.md#all-33-rpc-commands
273
- [thinking-reference]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.1/docs/api.md#models-state-and-compaction
274
- [usage]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.1/docs/usage.md
275
- [api]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.1/docs/api.md
276
- [examples]: https://github.com/cheenulabs/pi-agent-python-sdk/tree/v0.2.1/examples
277
- [contributing]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.1/CONTRIBUTING.md
278
- [discovery]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.1/docs/discovery.md
279
- [maintenance]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.1/docs/maintenance.md
280
- [releasing]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.1/docs/releasing.md
310
+ [release]: https://github.com/cheenulabs/pi-agent-python-sdk/releases/tag/v0.2.2
311
+ [metadata]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.2/pyproject.toml
312
+ [license]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.2/LICENSE
313
+ [compatibility]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.2/docs/compatibility.md
314
+ [errors]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.2/docs/errors.md
315
+ [stream-example]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.2/examples/stream.py
316
+ [constructor-options]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.2/docs/api.md#constructor-options
317
+ [extensions]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.2/docs/usage.md#using-your-own-extensions
318
+ [ui-example]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.2/examples/ui.py
319
+ [rpc]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.2/docs/rpc.md
320
+ [commands]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.2/docs/api.md#all-33-rpc-commands
321
+ [usage]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.2/docs/usage.md
322
+ [api]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.2/docs/api.md
323
+ [examples]: https://github.com/cheenulabs/pi-agent-python-sdk/tree/v0.2.2/examples
324
+ [contributing]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.2/CONTRIBUTING.md
325
+ [issues]: https://github.com/cheenulabs/pi-agent-python-sdk/issues
326
+ [security]: https://github.com/cheenulabs/pi-agent-python-sdk/security/advisories/new
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "pi-agent-python-sdk"
7
- version = "0.2.1"
7
+ version = "0.2.2"
8
8
  description = "Typed async and synchronous Python clients for Pi's agent RPC runtime"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -26,9 +26,9 @@ dependencies = []
26
26
 
27
27
  [project.urls]
28
28
  Homepage = "https://github.com/cheenulabs/pi-agent-python-sdk"
29
- Documentation = "https://github.com/cheenulabs/pi-agent-python-sdk/tree/v0.2.1/docs"
29
+ Documentation = "https://github.com/cheenulabs/pi-agent-python-sdk/tree/v0.2.2/docs"
30
30
  Issues = "https://github.com/cheenulabs/pi-agent-python-sdk/issues"
31
- Changelog = "https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.1/CHANGELOG.md"
31
+ Changelog = "https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.2/CHANGELOG.md"
32
32
 
33
33
  [dependency-groups]
34
34
  dev = [
@@ -13,7 +13,7 @@ from ._transport import _close_process_pipes, _wait_for_exit
13
13
  from .errors import PiProcessError, PiVersionError
14
14
 
15
15
  MINIMUM_PI_VERSION = "0.85.1"
16
- TESTED_PI_VERSION = "0.86.0"
16
+ TESTED_PI_VERSION = "0.86.1"
17
17
 
18
18
  # The client owns these options. In particular --print consumes an initial prompt.
19
19
  _RESERVED = {
@@ -1,4 +1,4 @@
1
- """Pi 0.86.0 wire annotations and small Python conveniences.
1
+ """Pi 0.86.1 wire annotations and small Python conveniences.
2
2
 
3
3
  Wire fields retain Pi's spelling and remain ordinary dictionaries. These
4
4
  annotations describe known shapes, not a recursive runtime validator: extensions