opencode-python-sdk 0.1.1__tar.gz → 0.1.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.
- opencode_python_sdk-0.1.3/CHANGELOG.md +18 -0
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/PKG-INFO +100 -1
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/README.md +97 -0
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/pyproject.toml +6 -0
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/src/opencode/__init__.py +52 -0
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/src/opencode/_client.py +23 -0
- opencode_python_sdk-0.1.3/src/opencode/_events.py +729 -0
- opencode_python_sdk-0.1.3/src/opencode/_pty.py +586 -0
- opencode_python_sdk-0.1.3/src/opencode/_rpc.py +482 -0
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/src/opencode/_streaming.py +22 -1
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/src/opencode/resources/experimental.py +3 -2
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/src/opencode/resources/pty.py +3 -2
- opencode_python_sdk-0.1.3/tests/test_events.py +396 -0
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/tests/test_live.py +65 -1
- opencode_python_sdk-0.1.3/tests/test_pty.py +236 -0
- opencode_python_sdk-0.1.3/tests/test_rpc.py +154 -0
- opencode_python_sdk-0.1.1/CHANGELOG.md +0 -9
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/.gitignore +0 -0
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/LICENSE +0 -0
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/api.md +0 -0
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/src/opencode/.generated.json +0 -0
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/src/opencode/_base_client.py +0 -0
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/src/opencode/_constants.py +0 -0
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/src/opencode/_errors.py +0 -0
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/src/opencode/_exceptions.py +0 -0
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/src/opencode/_models.py +0 -0
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/src/opencode/_pagination.py +0 -0
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/src/opencode/_qs.py +0 -0
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/src/opencode/_resource.py +0 -0
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/src/opencode/_server.py +0 -0
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/src/opencode/_types.py +0 -0
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/src/opencode/_unions.py +0 -0
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/src/opencode/_version.py +0 -0
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/src/opencode/py.typed +0 -0
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/src/opencode/resources/__init__.py +0 -0
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/src/opencode/resources/agent.py +0 -0
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/src/opencode/resources/command.py +0 -0
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/src/opencode/resources/config.py +0 -0
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/src/opencode/resources/credential.py +0 -0
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/src/opencode/resources/debug.py +0 -0
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/src/opencode/resources/event.py +0 -0
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/src/opencode/resources/file.py +0 -0
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/src/opencode/resources/form.py +0 -0
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/src/opencode/resources/generate.py +0 -0
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/src/opencode/resources/integration.py +0 -0
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/src/opencode/resources/location.py +0 -0
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/src/opencode/resources/mcp.py +0 -0
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/src/opencode/resources/message.py +0 -0
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/src/opencode/resources/migration.py +0 -0
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/src/opencode/resources/model.py +0 -0
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/src/opencode/resources/permission.py +0 -0
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/src/opencode/resources/plugin.py +0 -0
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/src/opencode/resources/project.py +0 -0
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/src/opencode/resources/provider.py +0 -0
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/src/opencode/resources/reference.py +0 -0
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/src/opencode/resources/rpc.py +0 -0
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/src/opencode/resources/server.py +0 -0
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/src/opencode/resources/session.py +0 -0
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/src/opencode/resources/shell.py +0 -0
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/src/opencode/resources/skill.py +0 -0
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/src/opencode/resources/vcs.py +0 -0
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/src/opencode/resources/voice.py +0 -0
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/src/opencode/resources/websearch.py +0 -0
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/src/opencode/resources/worktree.py +0 -0
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/src/opencode/types/__init__.py +0 -0
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/src/opencode/types/_generated.py +0 -0
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/tests/__init__.py +0 -0
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/tests/conftest.py +0 -0
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/tests/test_async_client.py +0 -0
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/tests/test_client.py +0 -0
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/tests/test_docs_coverage.py +0 -0
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/tests/test_encoding.py +0 -0
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/tests/test_models.py +0 -0
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/tests/test_pagination.py +0 -0
- {opencode_python_sdk-0.1.1 → opencode_python_sdk-0.1.3}/tests/test_streaming.py +0 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
Releases are published automatically on every merge to `main`. Release notes for each version are on the
|
|
4
|
+
[GitHub releases page](https://github.com/shrijayan/opencode-python-sdk/releases).
|
|
5
|
+
|
|
6
|
+
## Unreleased
|
|
7
|
+
|
|
8
|
+
- `client.events`: a shared event stream with one connection for all subscribers, bounded per-subscriber queues,
|
|
9
|
+
`server.connected` replay, `of_type` / `for_session` / `where` filters, `on_activity` keepalive hook, cancellation,
|
|
10
|
+
and opt-in reconnection with backoff (`EventHub(client, reconnect=True)`).
|
|
11
|
+
- `client.rpc(Definition)`: typed plugin RPC calls and event subscriptions declared with `RpcDefinition`,
|
|
12
|
+
`rpc_method` and `rpc_event`; RPC failures raise `RpcCallError` / `RpcCallInternalError`.
|
|
13
|
+
- `Stream.on_activity` and `Stream.interrupt()`.
|
|
14
|
+
|
|
15
|
+
## 0.1.0
|
|
16
|
+
|
|
17
|
+
First release, generated from OpenCode 2.1.2: sync and async clients for all 142 operations, typed models and
|
|
18
|
+
events, typed errors, pagination, event streams, retries, and the `OpencodeServer` launcher.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: opencode-python-sdk
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.3
|
|
4
4
|
Summary: Typed Python client for the OpenCode 2.x server API
|
|
5
5
|
Project-URL: Homepage, https://github.com/shrijayan/opencode-python-sdk
|
|
6
6
|
Project-URL: Documentation, https://shrijayan.github.io/opencode-python-sdk/
|
|
@@ -31,6 +31,8 @@ Requires-Dist: anyio<5,>=4.4
|
|
|
31
31
|
Requires-Dist: httpx<1,>=0.27
|
|
32
32
|
Requires-Dist: pydantic<3,>=2.12
|
|
33
33
|
Requires-Dist: typing-extensions>=4.12
|
|
34
|
+
Provides-Extra: pty
|
|
35
|
+
Requires-Dist: websockets<17,>=14; extra == 'pty'
|
|
34
36
|
Description-Content-Type: text/markdown
|
|
35
37
|
|
|
36
38
|
# opencode-python-sdk
|
|
@@ -204,6 +206,103 @@ Events are typed (`SessionCreatedEvent`, `SessionTextDeltaEvent`, and so on). Ev
|
|
|
204
206
|
not know arrive as `UnknownEvent` with all their fields kept. Streams apply only the connect timeout by default, since
|
|
205
207
|
they stay open between events.
|
|
206
208
|
|
|
209
|
+
### Shared event stream
|
|
210
|
+
|
|
211
|
+
`client.events` shares one connection among every subscriber, like `client.event` in the TypeScript client. The
|
|
212
|
+
connection opens with the first subscriber and closes when the last one leaves. Each subscriber has its own queue of
|
|
213
|
+
up to 4096 events; one that falls further behind fails with `EventOverflowError` without affecting the others. The
|
|
214
|
+
latest `server.connected` event is replayed to subscribers that join later.
|
|
215
|
+
|
|
216
|
+
```python
|
|
217
|
+
from opencode.types import SessionIdleEvent
|
|
218
|
+
|
|
219
|
+
with client.events.of_type(SessionIdleEvent).for_session(session.id) as idle:
|
|
220
|
+
client.session.prompt(session.id, text="Hello")
|
|
221
|
+
event = idle.get(timeout=300) # typed as SessionIdleEvent
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
- Filters chain: `of_type(*classes)` narrows the yielded type, `for_session(id)` keeps one session's events, and
|
|
225
|
+
`where(predicate)` takes any test. Entering the `with` block joins the stream, so nothing published after that is
|
|
226
|
+
missed.
|
|
227
|
+
- `subscribe(on_activity=callback)` calls `callback` for every chunk received, keepalive comments included, as a
|
|
228
|
+
liveness signal.
|
|
229
|
+
- `close()` (or leaving the `with` block) ends the subscription, also from another thread. In async code, cancel a wait
|
|
230
|
+
with `anyio.fail_after`, `asyncio.timeout` or a trio cancel scope; the subscription stays usable.
|
|
231
|
+
- Reconnection is opt-in: `EventHub(client, reconnect=True)` (or `AsyncEventHub`, or a `Reconnect(...)` policy) reopens
|
|
232
|
+
the connection with exponential backoff after connection errors, 5xx and 429. Subscribers see `server.connected`
|
|
233
|
+
once. **The stream is volatile**: events published while disconnected are lost, so re-read state through the API
|
|
234
|
+
after a reconnect when it matters.
|
|
235
|
+
|
|
236
|
+
The async hub works the same way under asyncio and trio:
|
|
237
|
+
|
|
238
|
+
```python
|
|
239
|
+
async with client.events.for_session(session.id) as events:
|
|
240
|
+
async for event in events:
|
|
241
|
+
print(event.type)
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
`client.event.subscribe()` still opens a dedicated connection.
|
|
245
|
+
|
|
246
|
+
### Plugin RPC
|
|
247
|
+
|
|
248
|
+
Declare a plugin RPC once as a class, then call it with typed inputs and outputs:
|
|
249
|
+
|
|
250
|
+
```python
|
|
251
|
+
from pydantic import BaseModel
|
|
252
|
+
from opencode import RpcCallError, RpcDefinition, rpc_event, rpc_method
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
class AddInput(BaseModel):
|
|
256
|
+
amount: int
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
class Total(BaseModel):
|
|
260
|
+
total: int
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
class Counter(RpcDefinition, id="counter"):
|
|
264
|
+
add = rpc_method(AddInput, Total)
|
|
265
|
+
reset = rpc_method(None, Total)
|
|
266
|
+
changed = rpc_event(Total)
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
counter = client.rpc(Counter)
|
|
270
|
+
try:
|
|
271
|
+
print(counter.call(Counter.add, AddInput(amount=2)).total)
|
|
272
|
+
except RpcCallError as error:
|
|
273
|
+
print(error.type, error.message, error.data)
|
|
274
|
+
|
|
275
|
+
with counter.subscribe(Counter.changed) as changes: # only rpc.counter.changed, with validated data
|
|
276
|
+
for change in changes:
|
|
277
|
+
print(change.data.total)
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
Any type pydantic validates works for inputs, outputs and event data. `rpc_method(..., errors={"not_found": Model})`
|
|
281
|
+
validates the `data` of declared errors. Failures raise `RpcCallError`; crashes and outputs that do not match the
|
|
282
|
+
declared type raise `RpcCallInternalError`. `counter.events()` yields every raw event of the RPC. The untyped
|
|
283
|
+
`client.rpc.call(rpc_id, method, input=...)` is still available.
|
|
284
|
+
|
|
285
|
+
## Terminals
|
|
286
|
+
|
|
287
|
+
`client.pty.attach()` opens an interactive connection to a PTY over a WebSocket. It needs the `pty` extra:
|
|
288
|
+
`pip install "opencode-python-sdk[pty]"`.
|
|
289
|
+
|
|
290
|
+
```python
|
|
291
|
+
pty = client.pty.create(command="/bin/sh").data
|
|
292
|
+
with client.pty.attach(pty.id) as term:
|
|
293
|
+
term.resize(120, 40)
|
|
294
|
+
term.send("echo hi\n")
|
|
295
|
+
for chunk in term: # output bytes, until the shell exits
|
|
296
|
+
print(chunk.decode(errors="replace"), end="")
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
`recv(timeout=...)` reads one chunk and returns `None` once the terminal has ended. `term.cursor` holds the output
|
|
300
|
+
position to pass as `cursor=` when reattaching; `cursor=-1` skips the replay of earlier output. Persistent terminals
|
|
301
|
+
work the same way through `client.experimental.persistent_pty.attach(pty_id, role=..., takeover=...)`. The async
|
|
302
|
+
client returns `AsyncPtyConnection` (asyncio only): `async with await client.pty.attach(...) as term`. A connection
|
|
303
|
+
the server refuses or closes abnormally raises `PtyConnectionError`. See
|
|
304
|
+
[`examples/terminal.py`](examples/terminal.py) for a full TTY bridge.
|
|
305
|
+
|
|
207
306
|
## Errors
|
|
208
307
|
|
|
209
308
|
Every error derives from `opencode.OpencodeError`. Errors the server declares are raised as their own class, with a
|
|
@@ -169,6 +169,103 @@ Events are typed (`SessionCreatedEvent`, `SessionTextDeltaEvent`, and so on). Ev
|
|
|
169
169
|
not know arrive as `UnknownEvent` with all their fields kept. Streams apply only the connect timeout by default, since
|
|
170
170
|
they stay open between events.
|
|
171
171
|
|
|
172
|
+
### Shared event stream
|
|
173
|
+
|
|
174
|
+
`client.events` shares one connection among every subscriber, like `client.event` in the TypeScript client. The
|
|
175
|
+
connection opens with the first subscriber and closes when the last one leaves. Each subscriber has its own queue of
|
|
176
|
+
up to 4096 events; one that falls further behind fails with `EventOverflowError` without affecting the others. The
|
|
177
|
+
latest `server.connected` event is replayed to subscribers that join later.
|
|
178
|
+
|
|
179
|
+
```python
|
|
180
|
+
from opencode.types import SessionIdleEvent
|
|
181
|
+
|
|
182
|
+
with client.events.of_type(SessionIdleEvent).for_session(session.id) as idle:
|
|
183
|
+
client.session.prompt(session.id, text="Hello")
|
|
184
|
+
event = idle.get(timeout=300) # typed as SessionIdleEvent
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
- Filters chain: `of_type(*classes)` narrows the yielded type, `for_session(id)` keeps one session's events, and
|
|
188
|
+
`where(predicate)` takes any test. Entering the `with` block joins the stream, so nothing published after that is
|
|
189
|
+
missed.
|
|
190
|
+
- `subscribe(on_activity=callback)` calls `callback` for every chunk received, keepalive comments included, as a
|
|
191
|
+
liveness signal.
|
|
192
|
+
- `close()` (or leaving the `with` block) ends the subscription, also from another thread. In async code, cancel a wait
|
|
193
|
+
with `anyio.fail_after`, `asyncio.timeout` or a trio cancel scope; the subscription stays usable.
|
|
194
|
+
- Reconnection is opt-in: `EventHub(client, reconnect=True)` (or `AsyncEventHub`, or a `Reconnect(...)` policy) reopens
|
|
195
|
+
the connection with exponential backoff after connection errors, 5xx and 429. Subscribers see `server.connected`
|
|
196
|
+
once. **The stream is volatile**: events published while disconnected are lost, so re-read state through the API
|
|
197
|
+
after a reconnect when it matters.
|
|
198
|
+
|
|
199
|
+
The async hub works the same way under asyncio and trio:
|
|
200
|
+
|
|
201
|
+
```python
|
|
202
|
+
async with client.events.for_session(session.id) as events:
|
|
203
|
+
async for event in events:
|
|
204
|
+
print(event.type)
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
`client.event.subscribe()` still opens a dedicated connection.
|
|
208
|
+
|
|
209
|
+
### Plugin RPC
|
|
210
|
+
|
|
211
|
+
Declare a plugin RPC once as a class, then call it with typed inputs and outputs:
|
|
212
|
+
|
|
213
|
+
```python
|
|
214
|
+
from pydantic import BaseModel
|
|
215
|
+
from opencode import RpcCallError, RpcDefinition, rpc_event, rpc_method
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
class AddInput(BaseModel):
|
|
219
|
+
amount: int
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
class Total(BaseModel):
|
|
223
|
+
total: int
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
class Counter(RpcDefinition, id="counter"):
|
|
227
|
+
add = rpc_method(AddInput, Total)
|
|
228
|
+
reset = rpc_method(None, Total)
|
|
229
|
+
changed = rpc_event(Total)
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
counter = client.rpc(Counter)
|
|
233
|
+
try:
|
|
234
|
+
print(counter.call(Counter.add, AddInput(amount=2)).total)
|
|
235
|
+
except RpcCallError as error:
|
|
236
|
+
print(error.type, error.message, error.data)
|
|
237
|
+
|
|
238
|
+
with counter.subscribe(Counter.changed) as changes: # only rpc.counter.changed, with validated data
|
|
239
|
+
for change in changes:
|
|
240
|
+
print(change.data.total)
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
Any type pydantic validates works for inputs, outputs and event data. `rpc_method(..., errors={"not_found": Model})`
|
|
244
|
+
validates the `data` of declared errors. Failures raise `RpcCallError`; crashes and outputs that do not match the
|
|
245
|
+
declared type raise `RpcCallInternalError`. `counter.events()` yields every raw event of the RPC. The untyped
|
|
246
|
+
`client.rpc.call(rpc_id, method, input=...)` is still available.
|
|
247
|
+
|
|
248
|
+
## Terminals
|
|
249
|
+
|
|
250
|
+
`client.pty.attach()` opens an interactive connection to a PTY over a WebSocket. It needs the `pty` extra:
|
|
251
|
+
`pip install "opencode-python-sdk[pty]"`.
|
|
252
|
+
|
|
253
|
+
```python
|
|
254
|
+
pty = client.pty.create(command="/bin/sh").data
|
|
255
|
+
with client.pty.attach(pty.id) as term:
|
|
256
|
+
term.resize(120, 40)
|
|
257
|
+
term.send("echo hi\n")
|
|
258
|
+
for chunk in term: # output bytes, until the shell exits
|
|
259
|
+
print(chunk.decode(errors="replace"), end="")
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
`recv(timeout=...)` reads one chunk and returns `None` once the terminal has ended. `term.cursor` holds the output
|
|
263
|
+
position to pass as `cursor=` when reattaching; `cursor=-1` skips the replay of earlier output. Persistent terminals
|
|
264
|
+
work the same way through `client.experimental.persistent_pty.attach(pty_id, role=..., takeover=...)`. The async
|
|
265
|
+
client returns `AsyncPtyConnection` (asyncio only): `async with await client.pty.attach(...) as term`. A connection
|
|
266
|
+
the server refuses or closes abnormally raises `PtyConnectionError`. See
|
|
267
|
+
[`examples/terminal.py`](examples/terminal.py) for a full TTY bridge.
|
|
268
|
+
|
|
172
269
|
## Errors
|
|
173
270
|
|
|
174
271
|
Every error derives from `opencode.OpencodeError`. Errors the server declares are raised as their own class, with a
|
|
@@ -39,6 +39,11 @@ Repository = "https://github.com/shrijayan/opencode-python-sdk"
|
|
|
39
39
|
Issues = "https://github.com/shrijayan/opencode-python-sdk/issues"
|
|
40
40
|
Changelog = "https://github.com/shrijayan/opencode-python-sdk/blob/main/CHANGELOG.md"
|
|
41
41
|
|
|
42
|
+
[project.optional-dependencies]
|
|
43
|
+
pty = [
|
|
44
|
+
"websockets>=14,<17",
|
|
45
|
+
]
|
|
46
|
+
|
|
42
47
|
[dependency-groups]
|
|
43
48
|
dev = [
|
|
44
49
|
"mypy>=1.18",
|
|
@@ -48,6 +53,7 @@ dev = [
|
|
|
48
53
|
"respx>=0.22",
|
|
49
54
|
"ruff>=0.14",
|
|
50
55
|
"trio>=0.31",
|
|
56
|
+
"websockets>=14",
|
|
51
57
|
]
|
|
52
58
|
docs = [
|
|
53
59
|
"mkdocs-material[imaging]>=9.6",
|
|
@@ -75,11 +75,39 @@ from ._exceptions import (
|
|
|
75
75
|
)
|
|
76
76
|
from ._models import BaseModel
|
|
77
77
|
from ._pagination import AsyncCursorPage, AsyncPaginator, SyncCursorPage
|
|
78
|
+
from ._pty import AsyncPtyConnection, PtyConnection, PtyConnectionError
|
|
78
79
|
from ._server import AsyncOpencodeServer, OpencodeServer, ServerStartError
|
|
79
80
|
from ._streaming import AsyncStream, Stream
|
|
80
81
|
from ._types import NOT_GIVEN, NotGiven
|
|
81
82
|
from ._version import __version__
|
|
82
83
|
|
|
84
|
+
# isort: split
|
|
85
|
+
# Hand-written helpers, kept apart from the generated error-import block above.
|
|
86
|
+
from ._events import (
|
|
87
|
+
SUBSCRIBER_CAPACITY,
|
|
88
|
+
AsyncEventHub,
|
|
89
|
+
AsyncSubscription,
|
|
90
|
+
EventHub,
|
|
91
|
+
EventOverflowError,
|
|
92
|
+
Reconnect,
|
|
93
|
+
Subscription,
|
|
94
|
+
session_id_of,
|
|
95
|
+
)
|
|
96
|
+
from ._rpc import (
|
|
97
|
+
AsyncRpcClient,
|
|
98
|
+
AsyncRpcEvents,
|
|
99
|
+
RpcCallError,
|
|
100
|
+
RpcCallInternalError,
|
|
101
|
+
RpcClient,
|
|
102
|
+
RpcDefinition,
|
|
103
|
+
RpcEventDefinition,
|
|
104
|
+
RpcEventPayload,
|
|
105
|
+
RpcEvents,
|
|
106
|
+
RpcMethod,
|
|
107
|
+
rpc_event,
|
|
108
|
+
rpc_method,
|
|
109
|
+
)
|
|
110
|
+
|
|
83
111
|
# <generated:api-version>
|
|
84
112
|
API_VERSION = "2.1.2"
|
|
85
113
|
"""The OpenCode server version this client was generated from."""
|
|
@@ -97,6 +125,7 @@ __all__ = [
|
|
|
97
125
|
"AsyncOpencode",
|
|
98
126
|
"AsyncOpencodeServer",
|
|
99
127
|
"AsyncPaginator",
|
|
128
|
+
"AsyncPtyConnection",
|
|
100
129
|
"AsyncStream",
|
|
101
130
|
"AuthenticationError",
|
|
102
131
|
"BadRequestError",
|
|
@@ -111,6 +140,8 @@ __all__ = [
|
|
|
111
140
|
"OpencodeError",
|
|
112
141
|
"OpencodeServer",
|
|
113
142
|
"PermissionDeniedError",
|
|
143
|
+
"PtyConnection",
|
|
144
|
+
"PtyConnectionError",
|
|
114
145
|
"RateLimitError",
|
|
115
146
|
"ServerStartError",
|
|
116
147
|
"ServiceUnavailableError",
|
|
@@ -119,6 +150,27 @@ __all__ = [
|
|
|
119
150
|
"UnprocessableEntityError",
|
|
120
151
|
"__version__",
|
|
121
152
|
"types",
|
|
153
|
+
# Shared event stream and typed plugin RPC
|
|
154
|
+
"SUBSCRIBER_CAPACITY",
|
|
155
|
+
"AsyncEventHub",
|
|
156
|
+
"AsyncRpcClient",
|
|
157
|
+
"AsyncRpcEvents",
|
|
158
|
+
"AsyncSubscription",
|
|
159
|
+
"EventHub",
|
|
160
|
+
"EventOverflowError",
|
|
161
|
+
"Reconnect",
|
|
162
|
+
"RpcCallError",
|
|
163
|
+
"RpcCallInternalError",
|
|
164
|
+
"RpcClient",
|
|
165
|
+
"RpcDefinition",
|
|
166
|
+
"RpcEventDefinition",
|
|
167
|
+
"RpcEventPayload",
|
|
168
|
+
"RpcEvents",
|
|
169
|
+
"RpcMethod",
|
|
170
|
+
"Subscription",
|
|
171
|
+
"rpc_event",
|
|
172
|
+
"rpc_method",
|
|
173
|
+
"session_id_of",
|
|
122
174
|
# <generated:error-exports>
|
|
123
175
|
"AgentNotFoundError",
|
|
124
176
|
"CommandExecutionError",
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
from functools import cached_property
|
|
3
4
|
from typing import TYPE_CHECKING
|
|
4
5
|
|
|
5
6
|
from typing_extensions import Self
|
|
6
7
|
|
|
7
8
|
from ._base_client import AsyncAPIClient, SyncAPIClient
|
|
8
9
|
from ._constants import DEFAULT_MAX_RETRIES, DEFAULT_TIMEOUT, DEFAULT_USERNAME
|
|
10
|
+
from ._events import AsyncEventHub, EventHub
|
|
11
|
+
from ._rpc import AsyncTypedRpcResource, TypedRpcResource
|
|
9
12
|
from ._types import NOT_GIVEN, NotGiven, Timeout
|
|
10
13
|
from .resources import AsyncResources, SyncResources
|
|
11
14
|
|
|
@@ -70,6 +73,16 @@ class Opencode(SyncAPIClient, SyncResources):
|
|
|
70
73
|
http_client=http_client,
|
|
71
74
|
)
|
|
72
75
|
|
|
76
|
+
@cached_property
|
|
77
|
+
def events(self) -> EventHub:
|
|
78
|
+
"""The shared event stream: one connection for every subscriber. See :class:`opencode.EventHub`."""
|
|
79
|
+
return EventHub(self)
|
|
80
|
+
|
|
81
|
+
@cached_property
|
|
82
|
+
def rpc(self) -> TypedRpcResource:
|
|
83
|
+
"""Plugin RPC calls: ``client.rpc.call(...)``, or ``client.rpc(Definition)`` for typed access."""
|
|
84
|
+
return TypedRpcResource(self)
|
|
85
|
+
|
|
73
86
|
def with_options(
|
|
74
87
|
self,
|
|
75
88
|
*,
|
|
@@ -138,6 +151,16 @@ class AsyncOpencode(AsyncAPIClient, AsyncResources):
|
|
|
138
151
|
http_client=http_client,
|
|
139
152
|
)
|
|
140
153
|
|
|
154
|
+
@cached_property
|
|
155
|
+
def events(self) -> AsyncEventHub:
|
|
156
|
+
"""The shared event stream: one connection for every subscriber. See :class:`opencode.AsyncEventHub`."""
|
|
157
|
+
return AsyncEventHub(self)
|
|
158
|
+
|
|
159
|
+
@cached_property
|
|
160
|
+
def rpc(self) -> AsyncTypedRpcResource:
|
|
161
|
+
"""Plugin RPC calls: ``client.rpc.call(...)``, or ``client.rpc(Definition)`` for typed access."""
|
|
162
|
+
return AsyncTypedRpcResource(self)
|
|
163
|
+
|
|
141
164
|
def with_options(
|
|
142
165
|
self,
|
|
143
166
|
*,
|