pi-agent-python-sdk 0.2.1__tar.gz → 0.2.3__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.
- {pi_agent_python_sdk-0.2.1 → pi_agent_python_sdk-0.2.3}/CHANGELOG.md +19 -0
- {pi_agent_python_sdk-0.2.1 → pi_agent_python_sdk-0.2.3}/PKG-INFO +168 -111
- pi_agent_python_sdk-0.2.3/README.md +337 -0
- {pi_agent_python_sdk-0.2.1 → pi_agent_python_sdk-0.2.3}/pyproject.toml +3 -3
- {pi_agent_python_sdk-0.2.1 → pi_agent_python_sdk-0.2.3}/src/pi_agent/_launch.py +1 -1
- {pi_agent_python_sdk-0.2.1 → pi_agent_python_sdk-0.2.3}/src/pi_agent/types.py +37 -1
- pi_agent_python_sdk-0.2.1/README.md +0 -280
- {pi_agent_python_sdk-0.2.1 → pi_agent_python_sdk-0.2.3}/.gitignore +0 -0
- {pi_agent_python_sdk-0.2.1 → pi_agent_python_sdk-0.2.3}/LICENSE +0 -0
- {pi_agent_python_sdk-0.2.1 → pi_agent_python_sdk-0.2.3}/src/pi_agent/__init__.py +0 -0
- {pi_agent_python_sdk-0.2.1 → pi_agent_python_sdk-0.2.3}/src/pi_agent/_collections.py +0 -0
- {pi_agent_python_sdk-0.2.1 → pi_agent_python_sdk-0.2.3}/src/pi_agent/_events.py +0 -0
- {pi_agent_python_sdk-0.2.1 → pi_agent_python_sdk-0.2.3}/src/pi_agent/_observation.py +0 -0
- {pi_agent_python_sdk-0.2.1 → pi_agent_python_sdk-0.2.3}/src/pi_agent/_runs.py +0 -0
- {pi_agent_python_sdk-0.2.1 → pi_agent_python_sdk-0.2.3}/src/pi_agent/_transport.py +0 -0
- {pi_agent_python_sdk-0.2.1 → pi_agent_python_sdk-0.2.3}/src/pi_agent/_usage.py +0 -0
- {pi_agent_python_sdk-0.2.1 → pi_agent_python_sdk-0.2.3}/src/pi_agent/client.py +0 -0
- {pi_agent_python_sdk-0.2.1 → pi_agent_python_sdk-0.2.3}/src/pi_agent/errors.py +0 -0
- {pi_agent_python_sdk-0.2.1 → pi_agent_python_sdk-0.2.3}/src/pi_agent/py.typed +0 -0
- {pi_agent_python_sdk-0.2.1 → pi_agent_python_sdk-0.2.3}/src/pi_agent/sync.py +0 -0
|
@@ -2,6 +2,25 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.2.3
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Describe Pi 0.87.0 context-edit session entries and optional model image input
|
|
10
|
+
limits in the typed wire annotations. Both remain Pi-owned behavior; unknown
|
|
11
|
+
fields continue to pass through unchanged.
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
|
|
15
|
+
- Update the tested Pi runtime to 0.87.0, retaining 0.85.1 as the minimum.
|
|
16
|
+
- Refresh the README's quick start, branding, and demonstration video.
|
|
17
|
+
|
|
18
|
+
## 0.2.2
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
|
|
22
|
+
- Update the tested Pi runtime to 0.86.1, retaining 0.85.1 as the minimum.
|
|
23
|
+
|
|
5
24
|
## 0.2.1
|
|
6
25
|
|
|
7
26
|
### Added
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: pi-agent-python-sdk
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.3
|
|
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.
|
|
6
|
+
Project-URL: Documentation, https://github.com/cheenulabs/pi-agent-python-sdk/tree/v0.2.3/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.
|
|
8
|
+
Project-URL: Changelog, https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.3/CHANGELOG.md
|
|
9
9
|
Author: cheenulabs
|
|
10
10
|
License-Expression: MIT
|
|
11
11
|
License-File: LICENSE
|
|
@@ -23,70 +23,80 @@ Description-Content-Type: text/markdown
|
|
|
23
23
|
|
|
24
24
|
# Pi Agent Python SDK
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
<p align="center">
|
|
27
|
+
<strong>Your terminal agent. Your Python API.</strong>
|
|
28
|
+
</p>
|
|
29
|
+
|
|
30
|
+
<p align="center">
|
|
31
|
+
<a href="https://github.com/cheenulabs/pi-agent-python-sdk">
|
|
32
|
+
<img alt="Pi Agent Python SDK" src="https://raw.githubusercontent.com/cheenulabs/pi-agent-python-sdk/v0.2.3/docs/logo.svg" width="160">
|
|
33
|
+
</a>
|
|
34
|
+
</p>
|
|
35
|
+
|
|
36
|
+
[][pypi]
|
|
27
37
|
[][metadata]
|
|
28
38
|
[][license]
|
|
29
39
|
|
|
30
|
-
|
|
31
|
-
|
|
40
|
+
[Pi](https://github.com/earendil-works/pi) is the coding agent that runs in your
|
|
41
|
+
terminal. This unofficial community SDK puts *your* Pi behind a typed sync and
|
|
42
|
+
async Python API — run prompts, stream events, and keep sessions going without
|
|
43
|
+
leaving Python.
|
|
32
44
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
45
|
+
<!-- Inline player: GitHub only auto-embeds bare user-attachments URLs
|
|
46
|
+
(repo-relative / raw / release URLs are stripped or become download links). -->
|
|
47
|
+
https://github.com/user-attachments/assets/c64dde3a-e812-42d4-a005-aa60df861e92
|
|
36
48
|
|
|
37
|
-
|
|
38
|
-
|
|
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)
|
|
49
|
+
```python
|
|
50
|
+
from pi_agent import PiClient
|
|
44
51
|
|
|
45
|
-
|
|
52
|
+
with PiClient() as pi:
|
|
53
|
+
print(pi.run("Explain the current project without changing files.").text)
|
|
54
|
+
```
|
|
46
55
|
|
|
47
|
-
|
|
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.
|
|
56
|
+
Requires an installed, configured Pi CLI — see [Prerequisites](#prerequisites).
|
|
51
57
|
|
|
52
|
-
|
|
58
|
+
[Prerequisites](#prerequisites) · [Quick start](#quick-start) ·
|
|
59
|
+
[Streaming](#streaming) · [Async](#async-usage) ·
|
|
60
|
+
[Configuration](#configuration) · [Thinking](#models-and-thinking) ·
|
|
61
|
+
[RPC](#rpc-access) · [Documentation](#documentation) ·
|
|
62
|
+
[Troubleshooting](#troubleshooting) · [Support](#support)
|
|
53
63
|
|
|
54
|
-
|
|
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.
|
|
64
|
+
## What you can do
|
|
59
65
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
66
|
+
- **Run prompts from Python** — get a final answer, or stream text, thinking, and
|
|
67
|
+
tool events as they happen.
|
|
68
|
+
- **Keep conversations going** — send follow-ups on the same client, or resume,
|
|
69
|
+
fork, and clone sessions.
|
|
70
|
+
- **Control the agent** — switch models, set thinking level, steer mid-run, and
|
|
71
|
+
compact context.
|
|
72
|
+
- **Reuse your Pi setup** — same configuration, tools, and extensions as the CLI,
|
|
73
|
+
with sync or async clients.
|
|
64
74
|
|
|
65
|
-
##
|
|
75
|
+
## Prerequisites
|
|
66
76
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
77
|
+
| Requirement | Notes |
|
|
78
|
+
| --- | --- |
|
|
79
|
+
| Python **3.11+** | Package metadata requires 3.11 or newer |
|
|
80
|
+
| Node.js **22.19.0+** | Required by Pi 0.87.0 |
|
|
81
|
+
| Pi **0.85.1+** | Minimum accepted version; **0.87.0** is the tested baseline |
|
|
82
|
+
| Model provider | Required; configure with the Pi CLI (see Quick start) |
|
|
73
83
|
|
|
74
84
|
## Quick start
|
|
75
85
|
|
|
76
|
-
Install Pi with Node.js **22.19.0 or newer
|
|
86
|
+
Install Pi with Node.js **22.19.0 or newer** (pin matches the tested baseline):
|
|
77
87
|
|
|
78
88
|
```sh
|
|
79
|
-
npm install -g @earendil-works/pi-coding-agent@0.
|
|
89
|
+
npm install -g @earendil-works/pi-coding-agent@0.87.0
|
|
80
90
|
pi --version
|
|
81
91
|
```
|
|
82
92
|
|
|
83
|
-
Run `pi` once to configure your provider and model
|
|
84
|
-
|
|
93
|
+
Run `pi` once to configure your provider and model. The SDK uses that
|
|
94
|
+
configuration when it starts Pi.
|
|
85
95
|
|
|
86
96
|
Install the Python package from [PyPI][pypi]:
|
|
87
97
|
|
|
88
98
|
```sh
|
|
89
|
-
python -m pip install pi-agent-python-sdk
|
|
99
|
+
python -m pip install pi-agent-python-sdk
|
|
90
100
|
```
|
|
91
101
|
|
|
92
102
|
The distribution is named `pi-agent-python-sdk`; import it as
|
|
@@ -101,8 +111,8 @@ with PiClient() as pi:
|
|
|
101
111
|
```
|
|
102
112
|
|
|
103
113
|
The context manager starts and closes Pi. `run()` waits for the conversation to
|
|
104
|
-
settle
|
|
105
|
-
|
|
114
|
+
settle. The result includes finalized messages, session identity, elapsed time,
|
|
115
|
+
and observed assistant usage.
|
|
106
116
|
|
|
107
117
|
Continue the conversation with another call on the same client:
|
|
108
118
|
|
|
@@ -131,9 +141,15 @@ with PiClient() as pi:
|
|
|
131
141
|
print(f"\nStop reason: {result.stop_reason}")
|
|
132
142
|
```
|
|
133
143
|
|
|
144
|
+
<details>
|
|
145
|
+
<summary>Streaming details</summary>
|
|
146
|
+
|
|
134
147
|
`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
|
|
136
|
-
handling timeouts and partial
|
|
148
|
+
recognize. Keep the stream inside its context: leaving early cleans up unfinished
|
|
149
|
+
work. See [errors and cancellation][errors] for handling timeouts and partial
|
|
150
|
+
results.
|
|
151
|
+
|
|
152
|
+
</details>
|
|
137
153
|
|
|
138
154
|
## Async usage
|
|
139
155
|
|
|
@@ -156,8 +172,13 @@ if __name__ == "__main__":
|
|
|
156
172
|
asyncio.run(main())
|
|
157
173
|
```
|
|
158
174
|
|
|
159
|
-
|
|
160
|
-
|
|
175
|
+
<details>
|
|
176
|
+
<summary>Async streaming</summary>
|
|
177
|
+
|
|
178
|
+
Use `async with pi.stream(...)`, `async for event in stream`, and
|
|
179
|
+
`await stream.result()`. See the [complete streaming example][stream-example].
|
|
180
|
+
|
|
181
|
+
</details>
|
|
161
182
|
|
|
162
183
|
## Configuration
|
|
163
184
|
|
|
@@ -171,46 +192,70 @@ with PiClient(cwd=".", no_session=True) as pi:
|
|
|
171
192
|
```
|
|
172
193
|
|
|
173
194
|
Leave `no_session` unset to preserve Pi's normal session persistence. Use
|
|
174
|
-
`
|
|
175
|
-
|
|
176
|
-
|
|
195
|
+
`session=` to open an existing session. For model overrides, see
|
|
196
|
+
[Models and thinking](#models-and-thinking).
|
|
197
|
+
|
|
198
|
+
<details>
|
|
199
|
+
<summary>More configuration</summary>
|
|
200
|
+
|
|
201
|
+
See [constructor options][constructor-options] for environment overrides,
|
|
202
|
+
executable paths, and deadlines.
|
|
177
203
|
|
|
178
204
|
Extensions are installed and configured through Pi. To load your own extension,
|
|
179
|
-
pass `extra_args=["--extension", "/absolute/path/to/your-extension.ts"]` to
|
|
180
|
-
client. See [using your own extensions][extensions]
|
|
181
|
-
|
|
205
|
+
pass `extra_args=["--extension", "/absolute/path/to/your-extension.ts"]` to
|
|
206
|
+
either client. See [using your own extensions][extensions] for details and
|
|
207
|
+
[extension UI][ui-example] for an interactive example.
|
|
208
|
+
|
|
209
|
+
</details>
|
|
182
210
|
|
|
183
211
|
## Models and thinking
|
|
184
212
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
213
|
+
By default the SDK uses whatever model you already configured in the Pi CLI.
|
|
214
|
+
Override it when you construct the client, or switch later on the same client.
|
|
215
|
+
Set the model and thinking level **before** `run()` or `stream()`.
|
|
216
|
+
|
|
217
|
+
Select a model at construction:
|
|
218
|
+
|
|
219
|
+
```python
|
|
220
|
+
from pi_agent import PiClient
|
|
221
|
+
|
|
222
|
+
with PiClient(provider="openai", model="gpt-5") as pi:
|
|
223
|
+
print(pi.run("Summarise this repo without changing files.").text)
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
Thinking levels depend on the current model. Query them, set one, then confirm
|
|
227
|
+
what Pi actually applied:
|
|
188
228
|
|
|
189
229
|
```python
|
|
190
230
|
from pi_agent import PiClient
|
|
191
231
|
|
|
192
232
|
with PiClient() as pi:
|
|
193
233
|
levels = pi.get_available_thinking_levels()
|
|
194
|
-
print("
|
|
234
|
+
print("available:", levels)
|
|
195
235
|
if "high" in levels:
|
|
196
236
|
pi.set_thinking_level("high")
|
|
197
|
-
print("
|
|
198
|
-
|
|
199
|
-
result = pi.run("Analyse this project's architecture without changing files.")
|
|
200
|
-
print(result.text)
|
|
237
|
+
print("effective:", pi.get_state()["thinkingLevel"])
|
|
238
|
+
print(pi.run("Analyse this project's architecture without changing files.").text)
|
|
201
239
|
```
|
|
202
240
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
levels and other controls.
|
|
241
|
+
Replace the example provider/model ids with ones from your Pi install
|
|
242
|
+
(`pi --list-models` or `get_available_models()`).
|
|
243
|
+
|
|
244
|
+
<details>
|
|
245
|
+
<summary>List models and switch after start</summary>
|
|
209
246
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
247
|
+
```python
|
|
248
|
+
from pi_agent import PiClient
|
|
249
|
+
|
|
250
|
+
with PiClient() as pi:
|
|
251
|
+
for model in pi.get_available_models():
|
|
252
|
+
print(model["provider"], model["id"])
|
|
253
|
+
selected = pi.set_model("openai", "gpt-5")
|
|
254
|
+
print("using", selected["provider"], selected["id"])
|
|
255
|
+
print(pi.run("Summarise this repo without changing files.").text)
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
</details>
|
|
214
259
|
|
|
215
260
|
## RPC access
|
|
216
261
|
|
|
@@ -223,7 +268,18 @@ Your Python application
|
|
|
223
268
|
Models · tools · extensions · sessions
|
|
224
269
|
```
|
|
225
270
|
|
|
226
|
-
|
|
271
|
+
Inspect session state without starting a model run:
|
|
272
|
+
|
|
273
|
+
```python
|
|
274
|
+
from pi_agent import PiClient
|
|
275
|
+
|
|
276
|
+
with PiClient() as pi:
|
|
277
|
+
state = pi.get_state()
|
|
278
|
+
print(state["sessionId"])
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
<details>
|
|
282
|
+
<summary>Which interface to use</summary>
|
|
227
283
|
|
|
228
284
|
| You need | Use |
|
|
229
285
|
| --- | --- |
|
|
@@ -235,29 +291,20 @@ Choose the interface that fits the work:
|
|
|
235
291
|
| A specific Pi operation | `get_state()`, `set_model()`, `fork()`, and other command methods |
|
|
236
292
|
| A raw command response envelope | `request()` |
|
|
237
293
|
|
|
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
294
|
Python arguments use `snake_case`; wire dictionaries retain Pi's `camelCase`
|
|
249
295
|
fields. `prompt()` acknowledges submission, which may be handled entirely by an
|
|
250
296
|
extension. It does not wait for a completed answer.
|
|
251
297
|
|
|
252
|
-
|
|
253
|
-
before starting the next. After using
|
|
254
|
-
use a fresh client for `run()` or
|
|
255
|
-
|
|
256
|
-
Pi terminal session.
|
|
298
|
+
Each client starts its own Pi subprocess. Use one client per conversation and
|
|
299
|
+
wait for each `run()` or stream to finish before starting the next. After using
|
|
300
|
+
`prompt()` for your own event handling, use a fresh client for `run()` or
|
|
301
|
+
`stream()` so results cannot include delayed events from earlier work.
|
|
257
302
|
|
|
258
303
|
See [RPC structure][rpc] for the protocol mapping and module layout, and
|
|
259
304
|
the [command reference][commands] for every method.
|
|
260
305
|
|
|
306
|
+
</details>
|
|
307
|
+
|
|
261
308
|
## Documentation
|
|
262
309
|
|
|
263
310
|
| Guide | Contents |
|
|
@@ -268,36 +315,46 @@ the [command reference][commands] for every method.
|
|
|
268
315
|
| [RPC structure][rpc] | How the Python client maps to Pi's protocol |
|
|
269
316
|
| [Compatibility][compatibility] | Runtime versions and platform validation |
|
|
270
317
|
| [Examples][examples] | Runnable sync, async, streaming, sessions, steering, and UI examples |
|
|
271
|
-
| [Release notes][release] | Changes included in 0.2.
|
|
318
|
+
| [Release notes][release] | Changes included in 0.2.3 |
|
|
272
319
|
|
|
273
320
|
Examples use your configured Pi and may make provider calls. Development checks
|
|
274
321
|
use an isolated local test provider; see [CONTRIBUTING.md][contributing] for
|
|
275
322
|
setup and validation commands.
|
|
276
323
|
|
|
277
|
-
|
|
278
|
-
|
|
324
|
+
## Troubleshooting
|
|
325
|
+
|
|
326
|
+
| Symptom | What to check |
|
|
327
|
+
| --- | --- |
|
|
328
|
+
| `pi` not found / launch fails | Ensure the Pi CLI is on `PATH`, or pass `executable=` to the client |
|
|
329
|
+
| Version rejected | Upgrade to Pi **0.85.1+**; prefer the tested baseline **0.87.0** |
|
|
330
|
+
| No model / auth errors | Run `pi` once and complete provider setup |
|
|
331
|
+
| Unexpected file or command changes | Review Pi tool/extension settings before automation |
|
|
332
|
+
|
|
333
|
+
## Support
|
|
334
|
+
|
|
335
|
+
- [Open an issue][issues] for bugs, questions, or compatibility reports.
|
|
336
|
+
- See [CONTRIBUTING.md][contributing] for local setup and pull requests.
|
|
337
|
+
- For security reports, open a [private security advisory][security].
|
|
279
338
|
|
|
280
339
|
## License
|
|
281
340
|
|
|
282
341
|
[MIT][license]
|
|
283
342
|
|
|
284
343
|
[pypi]: https://pypi.org/project/pi-agent-python-sdk/
|
|
285
|
-
[release]: https://github.com/cheenulabs/pi-agent-python-sdk/releases/tag/v0.2.
|
|
286
|
-
[metadata]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.
|
|
287
|
-
[license]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.
|
|
288
|
-
[compatibility]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.
|
|
289
|
-
[errors]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.
|
|
290
|
-
[stream-example]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.
|
|
291
|
-
[constructor-options]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.
|
|
292
|
-
[extensions]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.
|
|
293
|
-
[ui-example]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.
|
|
294
|
-
[rpc]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.
|
|
295
|
-
[commands]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.
|
|
296
|
-
[
|
|
297
|
-
[
|
|
298
|
-
[
|
|
299
|
-
[
|
|
300
|
-
[
|
|
301
|
-
[
|
|
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
|
|
344
|
+
[release]: https://github.com/cheenulabs/pi-agent-python-sdk/releases/tag/v0.2.3
|
|
345
|
+
[metadata]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.3/pyproject.toml
|
|
346
|
+
[license]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.3/LICENSE
|
|
347
|
+
[compatibility]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.3/docs/compatibility.md
|
|
348
|
+
[errors]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.3/docs/errors.md
|
|
349
|
+
[stream-example]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.3/examples/stream.py
|
|
350
|
+
[constructor-options]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.3/docs/api.md#constructor-options
|
|
351
|
+
[extensions]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.3/docs/usage.md#using-your-own-extensions
|
|
352
|
+
[ui-example]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.3/examples/ui.py
|
|
353
|
+
[rpc]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.3/docs/rpc.md
|
|
354
|
+
[commands]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.3/docs/api.md#all-33-rpc-commands
|
|
355
|
+
[usage]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.3/docs/usage.md
|
|
356
|
+
[api]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.3/docs/api.md
|
|
357
|
+
[examples]: https://github.com/cheenulabs/pi-agent-python-sdk/tree/v0.2.3/examples
|
|
358
|
+
[contributing]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.3/CONTRIBUTING.md
|
|
359
|
+
[issues]: https://github.com/cheenulabs/pi-agent-python-sdk/issues
|
|
360
|
+
[security]: https://github.com/cheenulabs/pi-agent-python-sdk/security/advisories/new
|
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
# Pi Agent Python SDK
|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
<strong>Your terminal agent. Your Python API.</strong>
|
|
5
|
+
</p>
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
<a href="https://github.com/cheenulabs/pi-agent-python-sdk">
|
|
9
|
+
<img alt="Pi Agent Python SDK" src="https://raw.githubusercontent.com/cheenulabs/pi-agent-python-sdk/v0.2.3/docs/logo.svg" width="160">
|
|
10
|
+
</a>
|
|
11
|
+
</p>
|
|
12
|
+
|
|
13
|
+
[][pypi]
|
|
14
|
+
[][metadata]
|
|
15
|
+
[][license]
|
|
16
|
+
|
|
17
|
+
[Pi](https://github.com/earendil-works/pi) is the coding agent that runs in your
|
|
18
|
+
terminal. This unofficial community SDK puts *your* Pi behind a typed sync and
|
|
19
|
+
async Python API — run prompts, stream events, and keep sessions going without
|
|
20
|
+
leaving Python.
|
|
21
|
+
|
|
22
|
+
<!-- Inline player: GitHub only auto-embeds bare user-attachments URLs
|
|
23
|
+
(repo-relative / raw / release URLs are stripped or become download links). -->
|
|
24
|
+
https://github.com/user-attachments/assets/c64dde3a-e812-42d4-a005-aa60df861e92
|
|
25
|
+
|
|
26
|
+
```python
|
|
27
|
+
from pi_agent import PiClient
|
|
28
|
+
|
|
29
|
+
with PiClient() as pi:
|
|
30
|
+
print(pi.run("Explain the current project without changing files.").text)
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Requires an installed, configured Pi CLI — see [Prerequisites](#prerequisites).
|
|
34
|
+
|
|
35
|
+
[Prerequisites](#prerequisites) · [Quick start](#quick-start) ·
|
|
36
|
+
[Streaming](#streaming) · [Async](#async-usage) ·
|
|
37
|
+
[Configuration](#configuration) · [Thinking](#models-and-thinking) ·
|
|
38
|
+
[RPC](#rpc-access) · [Documentation](#documentation) ·
|
|
39
|
+
[Troubleshooting](#troubleshooting) · [Support](#support)
|
|
40
|
+
|
|
41
|
+
## What you can do
|
|
42
|
+
|
|
43
|
+
- **Run prompts from Python** — get a final answer, or stream text, thinking, and
|
|
44
|
+
tool events as they happen.
|
|
45
|
+
- **Keep conversations going** — send follow-ups on the same client, or resume,
|
|
46
|
+
fork, and clone sessions.
|
|
47
|
+
- **Control the agent** — switch models, set thinking level, steer mid-run, and
|
|
48
|
+
compact context.
|
|
49
|
+
- **Reuse your Pi setup** — same configuration, tools, and extensions as the CLI,
|
|
50
|
+
with sync or async clients.
|
|
51
|
+
|
|
52
|
+
## Prerequisites
|
|
53
|
+
|
|
54
|
+
| Requirement | Notes |
|
|
55
|
+
| --- | --- |
|
|
56
|
+
| Python **3.11+** | Package metadata requires 3.11 or newer |
|
|
57
|
+
| Node.js **22.19.0+** | Required by Pi 0.87.0 |
|
|
58
|
+
| Pi **0.85.1+** | Minimum accepted version; **0.87.0** is the tested baseline |
|
|
59
|
+
| Model provider | Required; configure with the Pi CLI (see Quick start) |
|
|
60
|
+
|
|
61
|
+
## Quick start
|
|
62
|
+
|
|
63
|
+
Install Pi with Node.js **22.19.0 or newer** (pin matches the tested baseline):
|
|
64
|
+
|
|
65
|
+
```sh
|
|
66
|
+
npm install -g @earendil-works/pi-coding-agent@0.87.0
|
|
67
|
+
pi --version
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Run `pi` once to configure your provider and model. The SDK uses that
|
|
71
|
+
configuration when it starts Pi.
|
|
72
|
+
|
|
73
|
+
Install the Python package from [PyPI][pypi]:
|
|
74
|
+
|
|
75
|
+
```sh
|
|
76
|
+
python -m pip install pi-agent-python-sdk
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
The distribution is named `pi-agent-python-sdk`; import it as
|
|
80
|
+
`pi_agent`.
|
|
81
|
+
|
|
82
|
+
```python
|
|
83
|
+
from pi_agent import PiClient
|
|
84
|
+
|
|
85
|
+
with PiClient() as pi:
|
|
86
|
+
result = pi.run("Explain the current project without changing files.")
|
|
87
|
+
print(result.text)
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
The context manager starts and closes Pi. `run()` waits for the conversation to
|
|
91
|
+
settle. The result includes finalized messages, session identity, elapsed time,
|
|
92
|
+
and observed assistant usage.
|
|
93
|
+
|
|
94
|
+
Continue the conversation with another call on the same client:
|
|
95
|
+
|
|
96
|
+
```python
|
|
97
|
+
from pi_agent import PiClient
|
|
98
|
+
|
|
99
|
+
with PiClient() as pi:
|
|
100
|
+
print(pi.run("Explain this project's entry points without editing files.").text)
|
|
101
|
+
print(pi.run("Which of those entry points handles configuration?").text)
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Pi keeps the conversation context. Each result contains only the messages and
|
|
105
|
+
answer from that call; a call with no assistant output has empty text.
|
|
106
|
+
|
|
107
|
+
## Streaming
|
|
108
|
+
|
|
109
|
+
```python
|
|
110
|
+
from pi_agent import PiClient
|
|
111
|
+
|
|
112
|
+
with PiClient() as pi:
|
|
113
|
+
with pi.stream("Explain this project's entry points without editing files.") as stream:
|
|
114
|
+
for event in stream:
|
|
115
|
+
if event.text_delta is not None:
|
|
116
|
+
print(event.text_delta, end="", flush=True)
|
|
117
|
+
result = stream.result()
|
|
118
|
+
print(f"\nStop reason: {result.stop_reason}")
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
<details>
|
|
122
|
+
<summary>Streaming details</summary>
|
|
123
|
+
|
|
124
|
+
`event.raw` contains the full Pi event, including fields the SDK does not yet
|
|
125
|
+
recognize. Keep the stream inside its context: leaving early cleans up unfinished
|
|
126
|
+
work. See [errors and cancellation][errors] for handling timeouts and partial
|
|
127
|
+
results.
|
|
128
|
+
|
|
129
|
+
</details>
|
|
130
|
+
|
|
131
|
+
## Async usage
|
|
132
|
+
|
|
133
|
+
Use `AsyncPiClient` in applications that already run an event loop. Command
|
|
134
|
+
arguments and results match the synchronous client.
|
|
135
|
+
|
|
136
|
+
```python
|
|
137
|
+
import asyncio
|
|
138
|
+
|
|
139
|
+
from pi_agent import AsyncPiClient
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
async def main() -> None:
|
|
143
|
+
async with AsyncPiClient() as pi:
|
|
144
|
+
result = await pi.run("Explain the current project without changing files.")
|
|
145
|
+
print(result.text)
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
if __name__ == "__main__":
|
|
149
|
+
asyncio.run(main())
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
<details>
|
|
153
|
+
<summary>Async streaming</summary>
|
|
154
|
+
|
|
155
|
+
Use `async with pi.stream(...)`, `async for event in stream`, and
|
|
156
|
+
`await stream.result()`. See the [complete streaming example][stream-example].
|
|
157
|
+
|
|
158
|
+
</details>
|
|
159
|
+
|
|
160
|
+
## Configuration
|
|
161
|
+
|
|
162
|
+
Choose the project directory and whether to save the conversation:
|
|
163
|
+
|
|
164
|
+
```python
|
|
165
|
+
from pi_agent import PiClient
|
|
166
|
+
|
|
167
|
+
with PiClient(cwd=".", no_session=True) as pi:
|
|
168
|
+
print(pi.run("Describe this project without changing files.").text)
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Leave `no_session` unset to preserve Pi's normal session persistence. Use
|
|
172
|
+
`session=` to open an existing session. For model overrides, see
|
|
173
|
+
[Models and thinking](#models-and-thinking).
|
|
174
|
+
|
|
175
|
+
<details>
|
|
176
|
+
<summary>More configuration</summary>
|
|
177
|
+
|
|
178
|
+
See [constructor options][constructor-options] for environment overrides,
|
|
179
|
+
executable paths, and deadlines.
|
|
180
|
+
|
|
181
|
+
Extensions are installed and configured through Pi. To load your own extension,
|
|
182
|
+
pass `extra_args=["--extension", "/absolute/path/to/your-extension.ts"]` to
|
|
183
|
+
either client. See [using your own extensions][extensions] for details and
|
|
184
|
+
[extension UI][ui-example] for an interactive example.
|
|
185
|
+
|
|
186
|
+
</details>
|
|
187
|
+
|
|
188
|
+
## Models and thinking
|
|
189
|
+
|
|
190
|
+
By default the SDK uses whatever model you already configured in the Pi CLI.
|
|
191
|
+
Override it when you construct the client, or switch later on the same client.
|
|
192
|
+
Set the model and thinking level **before** `run()` or `stream()`.
|
|
193
|
+
|
|
194
|
+
Select a model at construction:
|
|
195
|
+
|
|
196
|
+
```python
|
|
197
|
+
from pi_agent import PiClient
|
|
198
|
+
|
|
199
|
+
with PiClient(provider="openai", model="gpt-5") as pi:
|
|
200
|
+
print(pi.run("Summarise this repo without changing files.").text)
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
Thinking levels depend on the current model. Query them, set one, then confirm
|
|
204
|
+
what Pi actually applied:
|
|
205
|
+
|
|
206
|
+
```python
|
|
207
|
+
from pi_agent import PiClient
|
|
208
|
+
|
|
209
|
+
with PiClient() as pi:
|
|
210
|
+
levels = pi.get_available_thinking_levels()
|
|
211
|
+
print("available:", levels)
|
|
212
|
+
if "high" in levels:
|
|
213
|
+
pi.set_thinking_level("high")
|
|
214
|
+
print("effective:", pi.get_state()["thinkingLevel"])
|
|
215
|
+
print(pi.run("Analyse this project's architecture without changing files.").text)
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
Replace the example provider/model ids with ones from your Pi install
|
|
219
|
+
(`pi --list-models` or `get_available_models()`).
|
|
220
|
+
|
|
221
|
+
<details>
|
|
222
|
+
<summary>List models and switch after start</summary>
|
|
223
|
+
|
|
224
|
+
```python
|
|
225
|
+
from pi_agent import PiClient
|
|
226
|
+
|
|
227
|
+
with PiClient() as pi:
|
|
228
|
+
for model in pi.get_available_models():
|
|
229
|
+
print(model["provider"], model["id"])
|
|
230
|
+
selected = pi.set_model("openai", "gpt-5")
|
|
231
|
+
print("using", selected["provider"], selected["id"])
|
|
232
|
+
print(pi.run("Summarise this repo without changing files.").text)
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
</details>
|
|
236
|
+
|
|
237
|
+
## RPC access
|
|
238
|
+
|
|
239
|
+
The SDK speaks Pi's existing JSONL protocol over stdin/stdout:
|
|
240
|
+
|
|
241
|
+
```text
|
|
242
|
+
Your Python application
|
|
243
|
+
PiClient / AsyncPiClient
|
|
244
|
+
pi --mode rpc
|
|
245
|
+
Models · tools · extensions · sessions
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
Inspect session state without starting a model run:
|
|
249
|
+
|
|
250
|
+
```python
|
|
251
|
+
from pi_agent import PiClient
|
|
252
|
+
|
|
253
|
+
with PiClient() as pi:
|
|
254
|
+
state = pi.get_state()
|
|
255
|
+
print(state["sessionId"])
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
<details>
|
|
259
|
+
<summary>Which interface to use</summary>
|
|
260
|
+
|
|
261
|
+
| You need | Use |
|
|
262
|
+
| --- | --- |
|
|
263
|
+
| A completed conversation result | `run()` |
|
|
264
|
+
| Events while a conversation runs | `stream()` |
|
|
265
|
+
| Prompt acknowledgement and your own event handling | `prompt()` with `events()` |
|
|
266
|
+
| Session events through the next settlement | `prompt_and_wait()` or `collect_events()` |
|
|
267
|
+
| Every event without retaining history | `on_event(callback)` |
|
|
268
|
+
| A specific Pi operation | `get_state()`, `set_model()`, `fork()`, and other command methods |
|
|
269
|
+
| A raw command response envelope | `request()` |
|
|
270
|
+
|
|
271
|
+
Python arguments use `snake_case`; wire dictionaries retain Pi's `camelCase`
|
|
272
|
+
fields. `prompt()` acknowledges submission, which may be handled entirely by an
|
|
273
|
+
extension. It does not wait for a completed answer.
|
|
274
|
+
|
|
275
|
+
Each client starts its own Pi subprocess. Use one client per conversation and
|
|
276
|
+
wait for each `run()` or stream to finish before starting the next. After using
|
|
277
|
+
`prompt()` for your own event handling, use a fresh client for `run()` or
|
|
278
|
+
`stream()` so results cannot include delayed events from earlier work.
|
|
279
|
+
|
|
280
|
+
See [RPC structure][rpc] for the protocol mapping and module layout, and
|
|
281
|
+
the [command reference][commands] for every method.
|
|
282
|
+
|
|
283
|
+
</details>
|
|
284
|
+
|
|
285
|
+
## Documentation
|
|
286
|
+
|
|
287
|
+
| Guide | Contents |
|
|
288
|
+
| --- | --- |
|
|
289
|
+
| [Usage][usage] | Sessions, images, concurrency, events, and extension UI |
|
|
290
|
+
| [API reference][api] | Constructors, commands, types, and results |
|
|
291
|
+
| [Errors and cancellation][errors] | Deadlines, partial results, cleanup, and recovery |
|
|
292
|
+
| [RPC structure][rpc] | How the Python client maps to Pi's protocol |
|
|
293
|
+
| [Compatibility][compatibility] | Runtime versions and platform validation |
|
|
294
|
+
| [Examples][examples] | Runnable sync, async, streaming, sessions, steering, and UI examples |
|
|
295
|
+
| [Release notes][release] | Changes included in 0.2.3 |
|
|
296
|
+
|
|
297
|
+
Examples use your configured Pi and may make provider calls. Development checks
|
|
298
|
+
use an isolated local test provider; see [CONTRIBUTING.md][contributing] for
|
|
299
|
+
setup and validation commands.
|
|
300
|
+
|
|
301
|
+
## Troubleshooting
|
|
302
|
+
|
|
303
|
+
| Symptom | What to check |
|
|
304
|
+
| --- | --- |
|
|
305
|
+
| `pi` not found / launch fails | Ensure the Pi CLI is on `PATH`, or pass `executable=` to the client |
|
|
306
|
+
| Version rejected | Upgrade to Pi **0.85.1+**; prefer the tested baseline **0.87.0** |
|
|
307
|
+
| No model / auth errors | Run `pi` once and complete provider setup |
|
|
308
|
+
| Unexpected file or command changes | Review Pi tool/extension settings before automation |
|
|
309
|
+
|
|
310
|
+
## Support
|
|
311
|
+
|
|
312
|
+
- [Open an issue][issues] for bugs, questions, or compatibility reports.
|
|
313
|
+
- See [CONTRIBUTING.md][contributing] for local setup and pull requests.
|
|
314
|
+
- For security reports, open a [private security advisory][security].
|
|
315
|
+
|
|
316
|
+
## License
|
|
317
|
+
|
|
318
|
+
[MIT][license]
|
|
319
|
+
|
|
320
|
+
[pypi]: https://pypi.org/project/pi-agent-python-sdk/
|
|
321
|
+
[release]: https://github.com/cheenulabs/pi-agent-python-sdk/releases/tag/v0.2.3
|
|
322
|
+
[metadata]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.3/pyproject.toml
|
|
323
|
+
[license]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.3/LICENSE
|
|
324
|
+
[compatibility]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.3/docs/compatibility.md
|
|
325
|
+
[errors]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.3/docs/errors.md
|
|
326
|
+
[stream-example]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.3/examples/stream.py
|
|
327
|
+
[constructor-options]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.3/docs/api.md#constructor-options
|
|
328
|
+
[extensions]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.3/docs/usage.md#using-your-own-extensions
|
|
329
|
+
[ui-example]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.3/examples/ui.py
|
|
330
|
+
[rpc]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.3/docs/rpc.md
|
|
331
|
+
[commands]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.3/docs/api.md#all-33-rpc-commands
|
|
332
|
+
[usage]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.3/docs/usage.md
|
|
333
|
+
[api]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.3/docs/api.md
|
|
334
|
+
[examples]: https://github.com/cheenulabs/pi-agent-python-sdk/tree/v0.2.3/examples
|
|
335
|
+
[contributing]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.3/CONTRIBUTING.md
|
|
336
|
+
[issues]: https://github.com/cheenulabs/pi-agent-python-sdk/issues
|
|
337
|
+
[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.
|
|
7
|
+
version = "0.2.3"
|
|
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.
|
|
29
|
+
Documentation = "https://github.com/cheenulabs/pi-agent-python-sdk/tree/v0.2.3/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.
|
|
31
|
+
Changelog = "https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.3/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.
|
|
16
|
+
TESTED_PI_VERSION = "0.87.0"
|
|
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.
|
|
1
|
+
"""Pi 0.87.0 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
|
|
@@ -221,6 +221,24 @@ class ModelPromptCache(TypedDict, total=False):
|
|
|
221
221
|
long: float
|
|
222
222
|
|
|
223
223
|
|
|
224
|
+
class ModelImageResizeOptions(TypedDict, total=False):
|
|
225
|
+
maxWidth: float
|
|
226
|
+
maxHeight: float
|
|
227
|
+
maxBytes: float
|
|
228
|
+
jpegQuality: float
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
class ModelImageInputLimits(TypedDict, total=False):
|
|
232
|
+
resize: ModelImageResizeOptions
|
|
233
|
+
maxPerMessage: float
|
|
234
|
+
maxPerRequest: float
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
class ModelInputLimits(TypedDict, total=False):
|
|
238
|
+
maxRequestBytes: float
|
|
239
|
+
images: ModelImageInputLimits
|
|
240
|
+
|
|
241
|
+
|
|
224
242
|
class Model(TypedDict):
|
|
225
243
|
id: str
|
|
226
244
|
name: str
|
|
@@ -230,6 +248,7 @@ class Model(TypedDict):
|
|
|
230
248
|
reasoning: bool
|
|
231
249
|
thinkingLevelMap: NotRequired[dict[ThinkingLevel, str | None]]
|
|
232
250
|
input: list[Literal["text", "image"]]
|
|
251
|
+
inputLimits: NotRequired[ModelInputLimits]
|
|
233
252
|
cost: ModelCost
|
|
234
253
|
contextWindow: float
|
|
235
254
|
maxTokens: float
|
|
@@ -378,6 +397,22 @@ class CustomMessageEntry(_EntryBase):
|
|
|
378
397
|
display: bool
|
|
379
398
|
|
|
380
399
|
|
|
400
|
+
# Keep the list arms separate so typing rejects mixed ToolCall and ImageContent lists.
|
|
401
|
+
ContextEditableContent: TypeAlias = (
|
|
402
|
+
str | list[TextContent | ImageContent] | list[TextContent | ThinkingContent | ToolCall]
|
|
403
|
+
)
|
|
404
|
+
|
|
405
|
+
|
|
406
|
+
class ContextEditReplacement(TypedDict):
|
|
407
|
+
content: ContextEditableContent
|
|
408
|
+
|
|
409
|
+
|
|
410
|
+
class ContextEditEntry(_EntryBase):
|
|
411
|
+
type: Literal["context_edit"]
|
|
412
|
+
targetId: str
|
|
413
|
+
replacement: ContextEditReplacement | None
|
|
414
|
+
|
|
415
|
+
|
|
381
416
|
class LabelEntry(_EntryBase):
|
|
382
417
|
type: Literal["label"]
|
|
383
418
|
targetId: str
|
|
@@ -398,6 +433,7 @@ SessionEntry: TypeAlias = (
|
|
|
398
433
|
| BranchSummaryEntry
|
|
399
434
|
| CustomEntry
|
|
400
435
|
| CustomMessageEntry
|
|
436
|
+
| ContextEditEntry
|
|
401
437
|
| LabelEntry
|
|
402
438
|
| SessionInfoEntry
|
|
403
439
|
)
|
|
@@ -1,280 +0,0 @@
|
|
|
1
|
-
# Pi Agent Python SDK
|
|
2
|
-
|
|
3
|
-
[][pypi]
|
|
4
|
-
[][metadata]
|
|
5
|
-
[][license]
|
|
6
|
-
|
|
7
|
-
**Use your installed Pi coding agent as a Python API. Stream responses,
|
|
8
|
-
continue conversations, and control sessions from Python.**
|
|
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.
|
|
13
|
-
|
|
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)
|
|
21
|
-
|
|
22
|
-
## Why use this?
|
|
23
|
-
|
|
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.
|
|
28
|
-
|
|
29
|
-
This is useful when you want to:
|
|
30
|
-
|
|
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.
|
|
36
|
-
|
|
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.
|
|
41
|
-
|
|
42
|
-
## What you can do
|
|
43
|
-
|
|
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.
|
|
50
|
-
|
|
51
|
-
## Quick start
|
|
52
|
-
|
|
53
|
-
Install Pi with Node.js **22.19.0 or newer**:
|
|
54
|
-
|
|
55
|
-
```sh
|
|
56
|
-
npm install -g @earendil-works/pi-coding-agent@0.86.0
|
|
57
|
-
pi --version
|
|
58
|
-
```
|
|
59
|
-
|
|
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.
|
|
62
|
-
|
|
63
|
-
Install the Python package from [PyPI][pypi]:
|
|
64
|
-
|
|
65
|
-
```sh
|
|
66
|
-
python -m pip install pi-agent-python-sdk==0.2.1
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
The distribution is named `pi-agent-python-sdk`; import it as
|
|
70
|
-
`pi_agent`.
|
|
71
|
-
|
|
72
|
-
```python
|
|
73
|
-
from pi_agent import PiClient
|
|
74
|
-
|
|
75
|
-
with PiClient() as pi:
|
|
76
|
-
result = pi.run("Explain the current project without changing files.")
|
|
77
|
-
print(result.text)
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
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.
|
|
83
|
-
|
|
84
|
-
Continue the conversation with another call on the same client:
|
|
85
|
-
|
|
86
|
-
```python
|
|
87
|
-
from pi_agent import PiClient
|
|
88
|
-
|
|
89
|
-
with PiClient() as pi:
|
|
90
|
-
print(pi.run("Explain this project's entry points without editing files.").text)
|
|
91
|
-
print(pi.run("Which of those entry points handles configuration?").text)
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
Pi keeps the conversation context. Each result contains only the messages and
|
|
95
|
-
answer from that call; a call with no assistant output has empty text.
|
|
96
|
-
|
|
97
|
-
## Streaming
|
|
98
|
-
|
|
99
|
-
```python
|
|
100
|
-
from pi_agent import PiClient
|
|
101
|
-
|
|
102
|
-
with PiClient() as pi:
|
|
103
|
-
with pi.stream("Explain this project's entry points without editing files.") as stream:
|
|
104
|
-
for event in stream:
|
|
105
|
-
if event.text_delta is not None:
|
|
106
|
-
print(event.text_delta, end="", flush=True)
|
|
107
|
-
result = stream.result()
|
|
108
|
-
print(f"\nStop reason: {result.stop_reason}")
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
`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
|
-
|
|
115
|
-
## Async usage
|
|
116
|
-
|
|
117
|
-
Use `AsyncPiClient` in applications that already run an event loop. Command
|
|
118
|
-
arguments and results match the synchronous client.
|
|
119
|
-
|
|
120
|
-
```python
|
|
121
|
-
import asyncio
|
|
122
|
-
|
|
123
|
-
from pi_agent import AsyncPiClient
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
async def main() -> None:
|
|
127
|
-
async with AsyncPiClient() as pi:
|
|
128
|
-
result = await pi.run("Explain the current project without changing files.")
|
|
129
|
-
print(result.text)
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
if __name__ == "__main__":
|
|
133
|
-
asyncio.run(main())
|
|
134
|
-
```
|
|
135
|
-
|
|
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].
|
|
138
|
-
|
|
139
|
-
## Configuration
|
|
140
|
-
|
|
141
|
-
Choose the project directory and whether to save the conversation:
|
|
142
|
-
|
|
143
|
-
```python
|
|
144
|
-
from pi_agent import PiClient
|
|
145
|
-
|
|
146
|
-
with PiClient(cwd=".", no_session=True) as pi:
|
|
147
|
-
print(pi.run("Describe this project without changing files.").text)
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
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.
|
|
154
|
-
|
|
155
|
-
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.
|
|
159
|
-
|
|
160
|
-
## Models and thinking
|
|
161
|
-
|
|
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:
|
|
165
|
-
|
|
166
|
-
```python
|
|
167
|
-
from pi_agent import PiClient
|
|
168
|
-
|
|
169
|
-
with PiClient() as pi:
|
|
170
|
-
levels = pi.get_available_thinking_levels()
|
|
171
|
-
print("Supported thinking levels:", levels)
|
|
172
|
-
if "high" in levels:
|
|
173
|
-
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)
|
|
178
|
-
```
|
|
179
|
-
|
|
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.
|
|
186
|
-
|
|
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.
|
|
191
|
-
|
|
192
|
-
## RPC access
|
|
193
|
-
|
|
194
|
-
The SDK speaks Pi's existing JSONL protocol over stdin/stdout:
|
|
195
|
-
|
|
196
|
-
```text
|
|
197
|
-
Your Python application
|
|
198
|
-
PiClient / AsyncPiClient
|
|
199
|
-
pi --mode rpc
|
|
200
|
-
Models · tools · extensions · sessions
|
|
201
|
-
```
|
|
202
|
-
|
|
203
|
-
Choose the interface that fits the work:
|
|
204
|
-
|
|
205
|
-
| You need | Use |
|
|
206
|
-
| --- | --- |
|
|
207
|
-
| A completed conversation result | `run()` |
|
|
208
|
-
| Events while a conversation runs | `stream()` |
|
|
209
|
-
| Prompt acknowledgement and your own event handling | `prompt()` with `events()` |
|
|
210
|
-
| Session events through the next settlement | `prompt_and_wait()` or `collect_events()` |
|
|
211
|
-
| Every event without retaining history | `on_event(callback)` |
|
|
212
|
-
| A specific Pi operation | `get_state()`, `set_model()`, `fork()`, and other command methods |
|
|
213
|
-
| A raw command response envelope | `request()` |
|
|
214
|
-
|
|
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
|
-
Python arguments use `snake_case`; wire dictionaries retain Pi's `camelCase`
|
|
226
|
-
fields. `prompt()` acknowledges submission, which may be handled entirely by an
|
|
227
|
-
extension. It does not wait for a completed answer.
|
|
228
|
-
|
|
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.
|
|
234
|
-
|
|
235
|
-
See [RPC structure][rpc] for the protocol mapping and module layout, and
|
|
236
|
-
the [command reference][commands] for every method.
|
|
237
|
-
|
|
238
|
-
## Documentation
|
|
239
|
-
|
|
240
|
-
| Guide | Contents |
|
|
241
|
-
| --- | --- |
|
|
242
|
-
| [Usage][usage] | Sessions, images, concurrency, events, and extension UI |
|
|
243
|
-
| [API reference][api] | Constructors, commands, types, and results |
|
|
244
|
-
| [Errors and cancellation][errors] | Deadlines, partial results, cleanup, and recovery |
|
|
245
|
-
| [RPC structure][rpc] | How the Python client maps to Pi's protocol |
|
|
246
|
-
| [Compatibility][compatibility] | Runtime versions and platform validation |
|
|
247
|
-
| [Examples][examples] | Runnable sync, async, streaming, sessions, steering, and UI examples |
|
|
248
|
-
| [Release notes][release] | Changes included in 0.2.1 |
|
|
249
|
-
|
|
250
|
-
Examples use your configured Pi and may make provider calls. Development checks
|
|
251
|
-
use an isolated local test provider; see [CONTRIBUTING.md][contributing] for
|
|
252
|
-
setup and validation commands.
|
|
253
|
-
|
|
254
|
-
Maintainers: [protocol discovery][discovery] ·
|
|
255
|
-
[maintenance][maintenance] · [release checklist][releasing].
|
|
256
|
-
|
|
257
|
-
## License
|
|
258
|
-
|
|
259
|
-
[MIT][license]
|
|
260
|
-
|
|
261
|
-
[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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|