pi-agent-python-sdk 0.1.0__tar.gz → 0.2.1__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 (20) hide show
  1. pi_agent_python_sdk-0.2.1/CHANGELOG.md +92 -0
  2. {pi_agent_python_sdk-0.1.0 → pi_agent_python_sdk-0.2.1}/PKG-INFO +114 -42
  3. {pi_agent_python_sdk-0.1.0 → pi_agent_python_sdk-0.2.1}/README.md +111 -39
  4. {pi_agent_python_sdk-0.1.0 → pi_agent_python_sdk-0.2.1}/pyproject.toml +3 -3
  5. {pi_agent_python_sdk-0.1.0 → pi_agent_python_sdk-0.2.1}/src/pi_agent/__init__.py +3 -0
  6. pi_agent_python_sdk-0.2.1/src/pi_agent/_collections.py +59 -0
  7. {pi_agent_python_sdk-0.1.0 → pi_agent_python_sdk-0.2.1}/src/pi_agent/_events.py +60 -17
  8. {pi_agent_python_sdk-0.1.0 → pi_agent_python_sdk-0.2.1}/src/pi_agent/_launch.py +1 -1
  9. pi_agent_python_sdk-0.2.1/src/pi_agent/_observation.py +95 -0
  10. {pi_agent_python_sdk-0.1.0 → pi_agent_python_sdk-0.2.1}/src/pi_agent/_runs.py +53 -28
  11. {pi_agent_python_sdk-0.1.0 → pi_agent_python_sdk-0.2.1}/src/pi_agent/_transport.py +118 -27
  12. {pi_agent_python_sdk-0.1.0 → pi_agent_python_sdk-0.2.1}/src/pi_agent/client.py +297 -51
  13. {pi_agent_python_sdk-0.1.0 → pi_agent_python_sdk-0.2.1}/src/pi_agent/errors.py +1 -1
  14. {pi_agent_python_sdk-0.1.0 → pi_agent_python_sdk-0.2.1}/src/pi_agent/sync.py +232 -37
  15. {pi_agent_python_sdk-0.1.0 → pi_agent_python_sdk-0.2.1}/src/pi_agent/types.py +62 -19
  16. pi_agent_python_sdk-0.1.0/CHANGELOG.md +0 -28
  17. {pi_agent_python_sdk-0.1.0 → pi_agent_python_sdk-0.2.1}/.gitignore +0 -0
  18. {pi_agent_python_sdk-0.1.0 → pi_agent_python_sdk-0.2.1}/LICENSE +0 -0
  19. {pi_agent_python_sdk-0.1.0 → pi_agent_python_sdk-0.2.1}/src/pi_agent/_usage.py +0 -0
  20. {pi_agent_python_sdk-0.1.0 → pi_agent_python_sdk-0.2.1}/src/pi_agent/py.typed +0 -0
@@ -0,0 +1,92 @@
1
+ # Changelog
2
+
3
+ ## Unreleased
4
+
5
+ ## 0.2.1
6
+
7
+ ### Added
8
+
9
+ - Stop process observations without closing Pi, then drain buffered records;
10
+ report scoped stop, discard, overflow, and process termination separately.
11
+
12
+ ### Fixed
13
+
14
+ - Drain the ready queue in each blocking iterator transfer to avoid finite-burst
15
+ overflow caused by repeated partial transfers. Queue limits remain unchanged;
16
+ the additional batch is bounded by the same count and byte budgets.
17
+ - Allow sequential async stream iterator reuse while retaining concurrent-reader
18
+ and result-drain protections.
19
+ - Keep a healthy client usable after locally rejected, unsent input, without
20
+ relaxing ownership or cleanup for commands that may have reached Pi.
21
+
22
+ ### Changed
23
+
24
+ - Update the tested Pi runtime to 0.86.0, retaining 0.85.1 as the minimum.
25
+ - Clarify Python interface choice, async event consumption, and structured-output
26
+ boundaries; demonstrate thinking, tool events, and unknown metadata.
27
+ - Describe system transcript messages, session usage entries, compaction system
28
+ snapshots, and model prompt-cache metadata in the wire annotations. Preserve
29
+ legacy optional fields and raw metadata; Pi still owns transcript and cache behavior.
30
+
31
+ ## 0.2.0
32
+
33
+ ### Breaking changes
34
+
35
+ - `prompt()` returns `None` after checked acknowledgement. Use `request("prompt", ...)`
36
+ for the response envelope and ID; `AcceptanceReceipt` is removed.
37
+ - `cycle_thinking_level()` and `export_html()` return their complete result
38
+ dictionaries, preserving unknown fields. Read `result["level"]` or `result["path"]`.
39
+ - Session mutations invalidate cached identity without an implicit state query.
40
+ Call `get_state()` explicitly when updated identity is needed.
41
+
42
+ ### Added
43
+
44
+ - TypeScript-style listeners and settlement helpers: `on_event()`,
45
+ `collect_events()`, `wait_for_idle()`, and `prompt_and_wait()` through both facades.
46
+ - Opt-in observation of original stderr/stdout bytes and all parsed RPC objects,
47
+ with bounded queues and explicit completion/loss status.
48
+ - Subscriptions before startup, including extension events and startup failures.
49
+ - Maintained TypeScript command/event comparison for source checkouts and installed
50
+ wheels across supported Python and operating-system versions.
51
+
52
+ ### Fixed
53
+
54
+ - Stream events before prompt acknowledgement while still requiring successful
55
+ acknowledgement and settlement before completing a result.
56
+ - Preserve UI callback causes; dialog expiry cancels only the dialog, and late
57
+ handler answers cannot override it.
58
+ - Deliver buffered event prefixes before terminal failures; preserve overflow
59
+ errors during concurrent blocking-context cleanup.
60
+ - Yield during finite output bursts and batch blocking reads; result-only runs
61
+ no longer buffer discarded progress. Slow consumers still fail explicitly.
62
+ - Preserve JSON-escaped lone surrogates on outbound commands and UI replies.
63
+
64
+ - Share deadline validation across runs, commands, collectors, and limits; invalid
65
+ types and integers too large for timers consistently raise `ValueError`.
66
+ - Document the retained run/stream conveniences and the reasons for their
67
+ internal ownership, session, and cleanup rules.
68
+
69
+ ## 0.1.0
70
+
71
+ - Introduce the `pi-agent-python-sdk` distribution with the `pi_agent` Python
72
+ import. Users of earlier source checkouts must update their imports.
73
+ - Keep the standalone SDK scoped to core RPC with zero runtime dependencies;
74
+ document loading caller-owned extensions through native Pi arguments.
75
+ - Prevent owned runs from claiming delayed events after low-level submissions.
76
+ - Bound retained run messages independently of event queues.
77
+ - Preserve unknown usage measurements, concatenate final text blocks directly,
78
+ and measure run latency from submission to settlement.
79
+ - Reject malformed known text deltas while preserving unknown event variants.
80
+ - Add `AsyncPiClient` and `PiClient` with explicit methods for all 33 Pi 0.85.1 RPC commands.
81
+ - Add typed wire payloads, future-only event subscriptions, extension dialogs,
82
+ streamed text, and settled results with session identity and observed usage.
83
+ - Preserve Pi configuration while owning process readiness, bounded I/O,
84
+ checked failures, cancellation cleanup, and offline compatibility checks.
85
+ - Add deterministic subprocess tests and isolated real-Pi integration using a
86
+ local faux provider, including retries, compaction, tools, and saved sessions.
87
+ - Add nine runnable examples and guides for the API, errors, compatibility,
88
+ dependency updates, and releases.
89
+ - Add Python/platform CI, Dependabot, daily latest-Pi checks, reviewed source
90
+ fingerprints, distribution inspection, and Trusted Publishing workflows.
91
+ - Verify published wheel and source hashes, and smoke-test index installations
92
+ before promoting the same artifacts from TestPyPI to PyPI.
@@ -1,11 +1,11 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: pi-agent-python-sdk
3
- Version: 0.1.0
3
+ Version: 0.2.1
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.1.0/docs
6
+ Project-URL: Documentation, https://github.com/cheenulabs/pi-agent-python-sdk/tree/v0.2.1/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.1.0/CHANGELOG.md
8
+ Project-URL: Changelog, https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.1/CHANGELOG.md
9
9
  Author: cheenulabs
10
10
  License-Expression: MIT
11
11
  License-File: LICENSE
@@ -23,39 +23,70 @@ 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
27
  [![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-3776AB?style=flat-square)][metadata]
27
28
  [![MIT license](https://img.shields.io/badge/license-MIT-blue?style=flat-square)][license]
28
29
 
29
- **Run Pi from Python. Stream responses, continue conversations, and control sessions.**
30
+ **Use your installed Pi coding agent as a Python API. Stream responses,
31
+ continue conversations, and control sessions from Python.**
30
32
 
31
33
  A community Python SDK for [Pi coding agent](https://github.com/earendil-works/pi).
32
- Use synchronous or asynchronous clients with typed access to Pi's RPC commands
33
- and no third-party Python runtime dependencies. Pi runs as a subprocess and keeps
34
- its usual models, authentication, tools, extensions, skills, and configuration.
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.
35
36
 
36
37
  > Requires Python **3.11+** and a separate Pi installation. The tested protocol
37
- > baseline is **Pi 0.85.1**; see [compatibility][compatibility] for version and
38
+ > baseline is **Pi 0.86.0**; see [compatibility][compatibility] for version and
38
39
  > platform scope.
39
40
 
40
41
  [Quick start](#quick-start) · [Streaming](#streaming) · [Async](#async-usage) ·
41
- [Configuration](#configuration) · [RPC](#rpc-access) · [Documentation](#documentation)
42
+ [Configuration](#configuration) · [Thinking](#models-and-thinking) ·
43
+ [RPC](#rpc-access) · [Documentation](#documentation)
44
+
45
+ ## Why use this?
46
+
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.
51
+
52
+ This is useful when you want to:
53
+
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.
59
+
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.
64
+
65
+ ## What you can do
66
+
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.
42
73
 
43
74
  ## Quick start
44
75
 
45
76
  Install Pi with Node.js **22.19.0 or newer**:
46
77
 
47
78
  ```sh
48
- npm install -g @earendil-works/pi-coding-agent@0.85.1
79
+ npm install -g @earendil-works/pi-coding-agent@0.86.0
49
80
  pi --version
50
81
  ```
51
82
 
52
83
  Run `pi` once to configure your provider and model using Pi's normal setup.
53
84
  The SDK uses that configuration when it starts Pi.
54
85
 
55
- Install the Python package:
86
+ Install the Python package from [PyPI][pypi]:
56
87
 
57
88
  ```sh
58
- python -m pip install pi-agent-python-sdk==0.1.0
89
+ python -m pip install pi-agent-python-sdk==0.2.1
59
90
  ```
60
91
 
61
92
  The distribution is named `pi-agent-python-sdk`; import it as
@@ -73,14 +104,18 @@ The context manager starts and closes Pi. `run()` waits for the conversation to
73
104
  settle, including retries and queued follow-ups. The result includes finalized
74
105
  messages, session identity, elapsed time, and observed assistant usage.
75
106
 
76
- ## What you can do
107
+ Continue the conversation with another call on the same client:
77
108
 
78
- - **Run and stream:** get a final answer or consume text, thinking, and tool events.
79
- - **Keep a conversation:** send follow-up prompts, resume sessions, fork, or clone.
80
- - **Control Pi:** select models, adjust thinking, steer work, compact context, and
81
- call all 33 RPC commands in the pinned baseline.
82
- - **Integrate with your application:** use sync or async clients, typed results,
83
- raw event dictionaries, and extension UI callbacks.
109
+ ```python
110
+ from pi_agent import PiClient
111
+
112
+ with PiClient() as pi:
113
+ print(pi.run("Explain this project's entry points without editing files.").text)
114
+ print(pi.run("Which of those entry points handles configuration?").text)
115
+ ```
116
+
117
+ Pi keeps the conversation context. Each result contains only the messages and
118
+ answer from that call; a call with no assistant output has empty text.
84
119
 
85
120
  ## Streaming
86
121
 
@@ -97,8 +132,7 @@ with PiClient() as pi:
97
132
  ```
98
133
 
99
134
  `event.raw` contains the full Pi event, including fields the SDK does not yet
100
- recognize. Keep the stream inside its context: leaving early clears queued input
101
- and aborts the work it owns. See [errors and cancellation][errors] for
135
+ recognize. Keep the stream inside its context: leaving early cleans up unfinished work. See [errors and cancellation][errors] for
102
136
  handling timeouts and partial results.
103
137
 
104
138
  ## Async usage
@@ -146,6 +180,38 @@ pass `extra_args=["--extension", "/absolute/path/to/your-extension.ts"]` to eith
146
180
  client. See [using your own extensions][extensions]
147
181
  for details and [extension UI][ui-example] for an interactive example.
148
182
 
183
+ ## Models and thinking
184
+
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:
188
+
189
+ ```python
190
+ from pi_agent import PiClient
191
+
192
+ with PiClient() as pi:
193
+ levels = pi.get_available_thinking_levels()
194
+ print("Supported thinking levels:", levels)
195
+ if "high" in levels:
196
+ 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)
201
+ ```
202
+
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.
209
+
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.
214
+
149
215
  ## RPC access
150
216
 
151
217
  The SDK speaks Pi's existing JSONL protocol over stdin/stdout:
@@ -164,6 +230,8 @@ Choose the interface that fits the work:
164
230
  | A completed conversation result | `run()` |
165
231
  | Events while a conversation runs | `stream()` |
166
232
  | Prompt acknowledgement and your own event handling | `prompt()` with `events()` |
233
+ | Session events through the next settlement | `prompt_and_wait()` or `collect_events()` |
234
+ | Every event without retaining history | `on_event(callback)` |
167
235
  | A specific Pi operation | `get_state()`, `set_model()`, `fork()`, and other command methods |
168
236
  | A raw command response envelope | `request()` |
169
237
 
@@ -181,10 +249,10 @@ Python arguments use `snake_case`; wire dictionaries retain Pi's `camelCase`
181
249
  fields. `prompt()` acknowledges submission, which may be handled entirely by an
182
250
  extension. It does not wait for a completed answer.
183
251
 
184
- One client owns one conversation at a time; create separate clients for
185
- independent conversations. After a low-level prompt submitted outside an owned
186
- run, use a fresh client for `run()` or `stream()` so events cannot be attributed
187
- to the wrong work. The SDK launches a new process and cannot attach to an existing
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
188
256
  Pi terminal session.
189
257
 
190
258
  See [RPC structure][rpc] for the protocol mapping and module layout, and
@@ -200,6 +268,7 @@ the [command reference][commands] for every method.
200
268
  | [RPC structure][rpc] | How the Python client maps to Pi's protocol |
201
269
  | [Compatibility][compatibility] | Runtime versions and platform validation |
202
270
  | [Examples][examples] | Runnable sync, async, streaming, sessions, steering, and UI examples |
271
+ | [Release notes][release] | Changes included in 0.2.1 |
203
272
 
204
273
  Examples use your configured Pi and may make provider calls. Development checks
205
274
  use an isolated local test provider; see [CONTRIBUTING.md][contributing] for
@@ -212,20 +281,23 @@ Maintainers: [protocol discovery][discovery] ·
212
281
 
213
282
  [MIT][license]
214
283
 
215
- [metadata]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.1.0/pyproject.toml
216
- [license]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.1.0/LICENSE
217
- [compatibility]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.1.0/docs/compatibility.md
218
- [errors]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.1.0/docs/errors.md
219
- [stream-example]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.1.0/examples/stream.py
220
- [constructor-options]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.1.0/docs/api.md#constructor-options
221
- [extensions]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.1.0/docs/usage.md#using-your-own-extensions
222
- [ui-example]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.1.0/examples/ui.py
223
- [rpc]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.1.0/docs/rpc.md
224
- [commands]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.1.0/docs/api.md#all-33-rpc-commands
225
- [usage]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.1.0/docs/usage.md
226
- [api]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.1.0/docs/api.md
227
- [examples]: https://github.com/cheenulabs/pi-agent-python-sdk/tree/v0.1.0/examples
228
- [contributing]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.1.0/CONTRIBUTING.md
229
- [discovery]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.1.0/docs/discovery.md
230
- [maintenance]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.1.0/docs/maintenance.md
231
- [releasing]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.1.0/docs/releasing.md
284
+ [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
@@ -1,38 +1,69 @@
1
1
  # Pi Agent Python SDK
2
2
 
3
+ [![PyPI](https://badge.fury.io/py/pi-agent-python-sdk.svg)][pypi]
3
4
  [![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-3776AB?style=flat-square)][metadata]
4
5
  [![MIT license](https://img.shields.io/badge/license-MIT-blue?style=flat-square)][license]
5
6
 
6
- **Run Pi from Python. Stream responses, continue conversations, and control sessions.**
7
+ **Use your installed Pi coding agent as a Python API. Stream responses,
8
+ continue conversations, and control sessions from Python.**
7
9
 
8
10
  A community Python SDK for [Pi coding agent](https://github.com/earendil-works/pi).
9
- Use synchronous or asynchronous clients with typed access to Pi's RPC commands
10
- and no third-party Python runtime dependencies. Pi runs as a subprocess and keeps
11
- its usual models, authentication, tools, extensions, skills, and configuration.
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.
12
13
 
13
14
  > Requires Python **3.11+** and a separate Pi installation. The tested protocol
14
- > baseline is **Pi 0.85.1**; see [compatibility][compatibility] for version and
15
+ > baseline is **Pi 0.86.0**; see [compatibility][compatibility] for version and
15
16
  > platform scope.
16
17
 
17
18
  [Quick start](#quick-start) · [Streaming](#streaming) · [Async](#async-usage) ·
18
- [Configuration](#configuration) · [RPC](#rpc-access) · [Documentation](#documentation)
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.
19
50
 
20
51
  ## Quick start
21
52
 
22
53
  Install Pi with Node.js **22.19.0 or newer**:
23
54
 
24
55
  ```sh
25
- npm install -g @earendil-works/pi-coding-agent@0.85.1
56
+ npm install -g @earendil-works/pi-coding-agent@0.86.0
26
57
  pi --version
27
58
  ```
28
59
 
29
60
  Run `pi` once to configure your provider and model using Pi's normal setup.
30
61
  The SDK uses that configuration when it starts Pi.
31
62
 
32
- Install the Python package:
63
+ Install the Python package from [PyPI][pypi]:
33
64
 
34
65
  ```sh
35
- python -m pip install pi-agent-python-sdk==0.1.0
66
+ python -m pip install pi-agent-python-sdk==0.2.1
36
67
  ```
37
68
 
38
69
  The distribution is named `pi-agent-python-sdk`; import it as
@@ -50,14 +81,18 @@ The context manager starts and closes Pi. `run()` waits for the conversation to
50
81
  settle, including retries and queued follow-ups. The result includes finalized
51
82
  messages, session identity, elapsed time, and observed assistant usage.
52
83
 
53
- ## What you can do
84
+ Continue the conversation with another call on the same client:
54
85
 
55
- - **Run and stream:** get a final answer or consume text, thinking, and tool events.
56
- - **Keep a conversation:** send follow-up prompts, resume sessions, fork, or clone.
57
- - **Control Pi:** select models, adjust thinking, steer work, compact context, and
58
- call all 33 RPC commands in the pinned baseline.
59
- - **Integrate with your application:** use sync or async clients, typed results,
60
- raw event dictionaries, and extension UI callbacks.
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.
61
96
 
62
97
  ## Streaming
63
98
 
@@ -74,8 +109,7 @@ with PiClient() as pi:
74
109
  ```
75
110
 
76
111
  `event.raw` contains the full Pi event, including fields the SDK does not yet
77
- recognize. Keep the stream inside its context: leaving early clears queued input
78
- and aborts the work it owns. See [errors and cancellation][errors] for
112
+ recognize. Keep the stream inside its context: leaving early cleans up unfinished work. See [errors and cancellation][errors] for
79
113
  handling timeouts and partial results.
80
114
 
81
115
  ## Async usage
@@ -123,6 +157,38 @@ pass `extra_args=["--extension", "/absolute/path/to/your-extension.ts"]` to eith
123
157
  client. See [using your own extensions][extensions]
124
158
  for details and [extension UI][ui-example] for an interactive example.
125
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
+
126
192
  ## RPC access
127
193
 
128
194
  The SDK speaks Pi's existing JSONL protocol over stdin/stdout:
@@ -141,6 +207,8 @@ Choose the interface that fits the work:
141
207
  | A completed conversation result | `run()` |
142
208
  | Events while a conversation runs | `stream()` |
143
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)` |
144
212
  | A specific Pi operation | `get_state()`, `set_model()`, `fork()`, and other command methods |
145
213
  | A raw command response envelope | `request()` |
146
214
 
@@ -158,10 +226,10 @@ Python arguments use `snake_case`; wire dictionaries retain Pi's `camelCase`
158
226
  fields. `prompt()` acknowledges submission, which may be handled entirely by an
159
227
  extension. It does not wait for a completed answer.
160
228
 
161
- One client owns one conversation at a time; create separate clients for
162
- independent conversations. After a low-level prompt submitted outside an owned
163
- run, use a fresh client for `run()` or `stream()` so events cannot be attributed
164
- to the wrong work. The SDK launches a new process and cannot attach to an existing
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
165
233
  Pi terminal session.
166
234
 
167
235
  See [RPC structure][rpc] for the protocol mapping and module layout, and
@@ -177,6 +245,7 @@ the [command reference][commands] for every method.
177
245
  | [RPC structure][rpc] | How the Python client maps to Pi's protocol |
178
246
  | [Compatibility][compatibility] | Runtime versions and platform validation |
179
247
  | [Examples][examples] | Runnable sync, async, streaming, sessions, steering, and UI examples |
248
+ | [Release notes][release] | Changes included in 0.2.1 |
180
249
 
181
250
  Examples use your configured Pi and may make provider calls. Development checks
182
251
  use an isolated local test provider; see [CONTRIBUTING.md][contributing] for
@@ -189,20 +258,23 @@ Maintainers: [protocol discovery][discovery] ·
189
258
 
190
259
  [MIT][license]
191
260
 
192
- [metadata]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.1.0/pyproject.toml
193
- [license]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.1.0/LICENSE
194
- [compatibility]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.1.0/docs/compatibility.md
195
- [errors]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.1.0/docs/errors.md
196
- [stream-example]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.1.0/examples/stream.py
197
- [constructor-options]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.1.0/docs/api.md#constructor-options
198
- [extensions]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.1.0/docs/usage.md#using-your-own-extensions
199
- [ui-example]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.1.0/examples/ui.py
200
- [rpc]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.1.0/docs/rpc.md
201
- [commands]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.1.0/docs/api.md#all-33-rpc-commands
202
- [usage]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.1.0/docs/usage.md
203
- [api]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.1.0/docs/api.md
204
- [examples]: https://github.com/cheenulabs/pi-agent-python-sdk/tree/v0.1.0/examples
205
- [contributing]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.1.0/CONTRIBUTING.md
206
- [discovery]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.1.0/docs/discovery.md
207
- [maintenance]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.1.0/docs/maintenance.md
208
- [releasing]: https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.1.0/docs/releasing.md
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
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "pi-agent-python-sdk"
7
- version = "0.1.0"
7
+ version = "0.2.1"
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.1.0/docs"
29
+ Documentation = "https://github.com/cheenulabs/pi-agent-python-sdk/tree/v0.2.1/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.1.0/CHANGELOG.md"
31
+ Changelog = "https://github.com/cheenulabs/pi-agent-python-sdk/blob/v0.2.1/CHANGELOG.md"
32
32
 
33
33
  [dependency-groups]
34
34
  dev = [
@@ -3,6 +3,7 @@
3
3
  Importing this package never launches Pi or changes its configuration.
4
4
  """
5
5
 
6
+ from ._observation import ObservationStatus, ProcessOutput
6
7
  from .client import AsyncPiClient
7
8
  from .errors import (
8
9
  PiBusyError,
@@ -27,6 +28,8 @@ __all__ = [
27
28
  "Event",
28
29
  "ImageContent",
29
30
  "Limits",
31
+ "ObservationStatus",
32
+ "ProcessOutput",
30
33
  "PiBusyError",
31
34
  "PiCommandError",
32
35
  "PiClient",