opencode-py 0.1.0__tar.gz → 0.2.0__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_py-0.2.0/.editorconfig +18 -0
- opencode_py-0.2.0/.gitattributes +36 -0
- opencode_py-0.2.0/.github/ISSUE_TEMPLATE/bug_report.yml +29 -0
- opencode_py-0.2.0/.github/ISSUE_TEMPLATE/feature_request.yml +26 -0
- opencode_py-0.2.0/.github/workflows/test.yml +62 -0
- opencode_py-0.2.0/.pre-commit-config.yaml +15 -0
- {opencode_py-0.1.0 → opencode_py-0.2.0}/AGENTS.md +60 -12
- opencode_py-0.2.0/CHANGELOG.md +22 -0
- opencode_py-0.2.0/CODE_OF_CONDUCT.md +63 -0
- opencode_py-0.2.0/CONTRIBUTING.md +44 -0
- opencode_py-0.2.0/LICENSE +21 -0
- opencode_py-0.1.0/README.md → opencode_py-0.2.0/PKG-INFO +74 -2
- opencode_py-0.1.0/PKG-INFO → opencode_py-0.2.0/README.md +39 -29
- {opencode_py-0.1.0 → opencode_py-0.2.0}/README.ru.md +10 -0
- opencode_py-0.2.0/RELEASE.md +52 -0
- opencode_py-0.2.0/SECURITY.md +15 -0
- opencode_py-0.2.0/demo.py +114 -0
- {opencode_py-0.1.0 → opencode_py-0.2.0}/live.py +1 -1
- {opencode_py-0.1.0 → opencode_py-0.2.0}/live_async.py +4 -2
- {opencode_py-0.1.0 → opencode_py-0.2.0}/live_streaming.py +3 -3
- opencode_py-0.2.0/pyproject.toml +76 -0
- opencode_py-0.2.0/scripts/check-release.py +95 -0
- {opencode_py-0.1.0 → opencode_py-0.2.0}/scripts/check-upstream.py +6 -4
- opencode_py-0.2.0/src/opencode/__init__.py +82 -0
- opencode_py-0.2.0/src/opencode/_async_client.py +944 -0
- {opencode_py-0.1.0 → opencode_py-0.2.0}/src/opencode/_async_opencode.py +23 -23
- opencode_py-0.2.0/src/opencode/_async_session.py +171 -0
- {opencode_py-0.1.0 → opencode_py-0.2.0}/src/opencode/_binary.py +9 -8
- opencode_py-0.2.0/src/opencode/_client.py +906 -0
- opencode_py-0.2.0/src/opencode/_errors.py +94 -0
- opencode_py-0.2.0/src/opencode/_logs.py +26 -0
- {opencode_py-0.1.0 → opencode_py-0.2.0}/src/opencode/_models.py +22 -20
- {opencode_py-0.1.0 → opencode_py-0.2.0}/src/opencode/_opencode.py +30 -29
- {opencode_py-0.1.0 → opencode_py-0.2.0}/src/opencode/_process.py +1 -1
- opencode_py-0.2.0/src/opencode/_response_models.py +242 -0
- {opencode_py-0.1.0 → opencode_py-0.2.0}/src/opencode/_server.py +8 -9
- {opencode_py-0.1.0 → opencode_py-0.2.0}/src/opencode/_session.py +64 -57
- {opencode_py-0.1.0 → opencode_py-0.2.0}/src/opencode/_tools.py +31 -25
- opencode_py-0.2.0/src/opencode/_types.py +28 -0
- opencode_py-0.2.0/src/opencode/py.typed +1 -0
- opencode_py-0.2.0/test_all.py +68 -0
- {opencode_py-0.1.0 → opencode_py-0.2.0}/test_live.py +16 -6
- opencode_py-0.2.0/tests/docker/Dockerfile +11 -0
- opencode_py-0.2.0/tests/docker/test_smoke.py +48 -0
- {opencode_py-0.1.0 → opencode_py-0.2.0}/tests/test_async_client.py +29 -13
- {opencode_py-0.1.0 → opencode_py-0.2.0}/tests/test_client.py +12 -16
- {opencode_py-0.1.0 → opencode_py-0.2.0}/tests/test_opencode.py +28 -13
- {opencode_py-0.1.0 → opencode_py-0.2.0}/web/server.py +7 -7
- opencode_py-0.1.0/.github/workflows/test.yml +0 -30
- opencode_py-0.1.0/demo.py +0 -94
- opencode_py-0.1.0/pyproject.toml +0 -47
- opencode_py-0.1.0/src/opencode/__init__.py +0 -45
- opencode_py-0.1.0/src/opencode/_async_client.py +0 -538
- opencode_py-0.1.0/src/opencode/_async_session.py +0 -155
- opencode_py-0.1.0/src/opencode/_client.py +0 -532
- opencode_py-0.1.0/src/opencode/_errors.py +0 -20
- opencode_py-0.1.0/test_all.py +0 -56
- {opencode_py-0.1.0 → opencode_py-0.2.0}/.github/workflows/publish.yml +0 -0
- {opencode_py-0.1.0 → opencode_py-0.2.0}/.gitignore +0 -0
- {opencode_py-0.1.0 → opencode_py-0.2.0}/docs/opencode-docs-ru.md +0 -0
- {opencode_py-0.1.0 → opencode_py-0.2.0}/src/opencode/__main__.py +0 -0
- {opencode_py-0.1.0 → opencode_py-0.2.0}/web/index.html +0 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
root = true
|
|
2
|
+
|
|
3
|
+
[*]
|
|
4
|
+
end_of_line = lf
|
|
5
|
+
insert_final_newline = true
|
|
6
|
+
trim_trailing_whitespace = true
|
|
7
|
+
charset = utf-8
|
|
8
|
+
indent_style = space
|
|
9
|
+
indent_size = 4
|
|
10
|
+
|
|
11
|
+
[*.md]
|
|
12
|
+
trim_trailing_whitespace = false
|
|
13
|
+
|
|
14
|
+
[*.{yml,yaml}]
|
|
15
|
+
indent_size = 2
|
|
16
|
+
|
|
17
|
+
[Makefile]
|
|
18
|
+
indent_style = tab
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
* text=auto eol=lf
|
|
2
|
+
|
|
3
|
+
# Python
|
|
4
|
+
*.py text
|
|
5
|
+
*.pyi text
|
|
6
|
+
*.pyw text
|
|
7
|
+
|
|
8
|
+
# Markdown
|
|
9
|
+
*.md text
|
|
10
|
+
*.mdx text
|
|
11
|
+
|
|
12
|
+
# Config
|
|
13
|
+
*.toml text
|
|
14
|
+
*.ini text
|
|
15
|
+
*.cfg text
|
|
16
|
+
*.yml text
|
|
17
|
+
*.yaml text
|
|
18
|
+
*.json text
|
|
19
|
+
|
|
20
|
+
# Git
|
|
21
|
+
.gitattributes text
|
|
22
|
+
.gitignore text
|
|
23
|
+
|
|
24
|
+
# Batch scripts (Windows needs CRLF)
|
|
25
|
+
*.bat text eol=crlf
|
|
26
|
+
*.cmd text eol=crlf
|
|
27
|
+
|
|
28
|
+
# Shell scripts (must stay LF)
|
|
29
|
+
*.sh text eol=lf
|
|
30
|
+
|
|
31
|
+
# Binaries
|
|
32
|
+
*.png binary
|
|
33
|
+
*.jpg binary
|
|
34
|
+
*.ico binary
|
|
35
|
+
*.exe binary
|
|
36
|
+
*.dll binary
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
name: Bug Report
|
|
2
|
+
description: Report a bug or unexpected behavior
|
|
3
|
+
labels: ["bug"]
|
|
4
|
+
|
|
5
|
+
body:
|
|
6
|
+
- type: textarea
|
|
7
|
+
id: description
|
|
8
|
+
attributes:
|
|
9
|
+
label: Description
|
|
10
|
+
description: What happened?
|
|
11
|
+
validations:
|
|
12
|
+
required: true
|
|
13
|
+
|
|
14
|
+
- type: textarea
|
|
15
|
+
id: reproduction
|
|
16
|
+
attributes:
|
|
17
|
+
label: Steps to reproduce
|
|
18
|
+
description: Minimal code or commands to reproduce.
|
|
19
|
+
render: python
|
|
20
|
+
|
|
21
|
+
- type: textarea
|
|
22
|
+
id: environment
|
|
23
|
+
attributes:
|
|
24
|
+
label: Environment
|
|
25
|
+
description: |
|
|
26
|
+
- OS: [e.g. Windows 11, Ubuntu 22.04]
|
|
27
|
+
- Python version:
|
|
28
|
+
- opencode-py version:
|
|
29
|
+
- opencode version (if relevant):
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
name: Feature Request
|
|
2
|
+
description: Suggest an idea for this project
|
|
3
|
+
labels: ["enhancement"]
|
|
4
|
+
|
|
5
|
+
body:
|
|
6
|
+
- type: textarea
|
|
7
|
+
id: problem
|
|
8
|
+
attributes:
|
|
9
|
+
label: Problem
|
|
10
|
+
description: What problem does this solve?
|
|
11
|
+
validations:
|
|
12
|
+
required: true
|
|
13
|
+
|
|
14
|
+
- type: textarea
|
|
15
|
+
id: solution
|
|
16
|
+
attributes:
|
|
17
|
+
label: Proposed solution
|
|
18
|
+
description: How would you like it to work?
|
|
19
|
+
validations:
|
|
20
|
+
required: true
|
|
21
|
+
|
|
22
|
+
- type: textarea
|
|
23
|
+
id: alternatives
|
|
24
|
+
attributes:
|
|
25
|
+
label: Alternatives
|
|
26
|
+
description: What alternatives have you considered?
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
name: Test
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [master, main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [master, main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
runs-on: ${{ matrix.os }}
|
|
12
|
+
strategy:
|
|
13
|
+
matrix:
|
|
14
|
+
os: [ubuntu-latest, windows-latest]
|
|
15
|
+
python-version: ["3.10", "3.11", "3.12", "3.13"]
|
|
16
|
+
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
|
|
20
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
21
|
+
uses: actions/setup-python@v5
|
|
22
|
+
with:
|
|
23
|
+
python-version: ${{ matrix.python-version }}
|
|
24
|
+
|
|
25
|
+
- name: Install dependencies
|
|
26
|
+
run: |
|
|
27
|
+
pip install -e ".[dev]"
|
|
28
|
+
|
|
29
|
+
- name: Lint with ruff
|
|
30
|
+
run: ruff check .
|
|
31
|
+
|
|
32
|
+
- name: Type check with mypy
|
|
33
|
+
run: mypy src/
|
|
34
|
+
|
|
35
|
+
- name: Run unit tests
|
|
36
|
+
run: pytest tests/ -v
|
|
37
|
+
|
|
38
|
+
integration-docker:
|
|
39
|
+
runs-on: ubuntu-latest
|
|
40
|
+
timeout-minutes: 15
|
|
41
|
+
steps:
|
|
42
|
+
- uses: actions/checkout@v4
|
|
43
|
+
|
|
44
|
+
- name: Set up Python 3.12
|
|
45
|
+
uses: actions/setup-python@v5
|
|
46
|
+
with:
|
|
47
|
+
python-version: "3.12"
|
|
48
|
+
|
|
49
|
+
- name: Build wheel
|
|
50
|
+
run: |
|
|
51
|
+
pip install build
|
|
52
|
+
python -m build --wheel
|
|
53
|
+
|
|
54
|
+
- name: Build Docker image
|
|
55
|
+
run: docker build -t opencode-py-test tests/docker/
|
|
56
|
+
|
|
57
|
+
- name: Run smoke test
|
|
58
|
+
run: |
|
|
59
|
+
docker run --rm \
|
|
60
|
+
-v "${{ github.workspace }}/dist:/dist" \
|
|
61
|
+
opencode-py-test \
|
|
62
|
+
bash -c "pip install /dist/*.whl && python test_smoke.py"
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
repos:
|
|
2
|
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
3
|
+
rev: v0.5.0
|
|
4
|
+
hooks:
|
|
5
|
+
- id: ruff
|
|
6
|
+
args: [--fix]
|
|
7
|
+
- id: ruff-format
|
|
8
|
+
|
|
9
|
+
- repo: https://github.com/pre-commit/mirrors-mypy
|
|
10
|
+
rev: v1.10.0
|
|
11
|
+
hooks:
|
|
12
|
+
- id: mypy
|
|
13
|
+
args: [src/]
|
|
14
|
+
additional_dependencies: [httpx]
|
|
15
|
+
pass_filenames: false
|
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
Python SDK for [Opencode](https://opencode.ai) — a PyPI package (`opencode-py`) that launches an `opencode serve` subprocess and provides both high-level and low-level APIs.
|
|
6
6
|
|
|
7
|
-
**Current version**: 0.
|
|
7
|
+
**Current version**: 0.2.0-dev
|
|
8
8
|
**Python**: >=3.10
|
|
9
|
-
**Dependencies**:
|
|
9
|
+
**Dependencies**: `httpx>=0.27.0`, `pydantic>=2.0.0`, `typing-extensions>=4.6.0`
|
|
10
10
|
**Build**: hatchling
|
|
11
11
|
|
|
12
12
|
## Repository
|
|
@@ -23,20 +23,24 @@ Python SDK for [Opencode](https://opencode.ai) — a PyPI package (`opencode-py`
|
|
|
23
23
|
```
|
|
24
24
|
opencode-py/
|
|
25
25
|
├── src/opencode/
|
|
26
|
-
│ ├── __init__.py # Public API exports
|
|
26
|
+
│ ├── __init__.py # Public API exports, calls setup_logging()
|
|
27
27
|
│ ├── __main__.py # python -m opencode "question"
|
|
28
28
|
│ ├── _opencode.py # Opencode class + opencode() convenience fn
|
|
29
29
|
│ ├── _async_opencode.py # AsyncOpendcode class + async_opencode()
|
|
30
|
-
│ ├── _client.py # OpencodeClient — sync REST (
|
|
31
|
-
│ ├── _async_client.py # AsyncOpendcodeClient — async REST
|
|
30
|
+
│ ├── _client.py # OpencodeClient — sync REST (typed models, retry)
|
|
31
|
+
│ ├── _async_client.py # AsyncOpendcodeClient — async REST (typed models, retry)
|
|
32
32
|
│ ├── _server.py # OpencodeServer — subprocess lifecycle
|
|
33
33
|
│ ├── _session.py # Session — sync conversation management
|
|
34
34
|
│ ├── _async_session.py # AsyncSession — async conversation management
|
|
35
35
|
│ ├── _binary.py # Binary find in PATH + GitHub download
|
|
36
36
|
│ ├── _process.py # Cross-platform process termination
|
|
37
|
-
│ ├── _models.py # TypedDict types (
|
|
37
|
+
│ ├── _models.py # TypedDict types (SessionMessage, etc.)
|
|
38
|
+
│ ├── _response_models.py # Pydantic BaseModel response types (all endpoints)
|
|
39
|
+
│ ├── _types.py # NotGiven sentinel
|
|
40
|
+
│ ├── _logs.py # Logging via OPENCODE_LOG env var
|
|
38
41
|
│ ├── _tools.py # ToolExecutor — run tools locally with permissions
|
|
39
|
-
│
|
|
42
|
+
│ ├── _errors.py # Typed exception hierarchy (10+ classes)
|
|
43
|
+
│ └── py.typed # PEP 561 marker for type checkers
|
|
40
44
|
├── tests/
|
|
41
45
|
│ ├── test_client.py # 11 unit tests (sync, httpx MockTransport)
|
|
42
46
|
│ ├── test_async_client.py # 11 unit tests (async, httpx MockTransport)
|
|
@@ -90,20 +94,26 @@ fb4b884 feat: initial Python SDK for Opencode
|
|
|
90
94
|
- 31/31 unit tests passing (sync + async)
|
|
91
95
|
- Python 3.10 compatibility (`NotRequired` via `typing_extensions`)
|
|
92
96
|
- `live.py` (sync), `live_async.py`, `live_streaming.py` — interactive dialog scripts with `atexit` cleanup
|
|
97
|
+
- **Pydantic response models** — `HealthResponse`, `SessionResponse`, `FileContentResponse`, `ProviderResponse`, `V1SessionResponse` and more
|
|
98
|
+
- **Retry logic** — exponential backoff with jitter, retries on 408/409/429/5xx and timeouts
|
|
99
|
+
- **Typed error hierarchy** — `APIStatusError` → `BadRequestError`, `RateLimitError`, `InternalServerError`, etc.
|
|
100
|
+
- **Logging** — `OPENCODE_LOG=debug` enables httpx debug logging
|
|
101
|
+
- **`py.typed` marker** — PEP 561 compliance for type checkers
|
|
102
|
+
- **`copy()`/`with_options()`** — immutable client cloning with overrides
|
|
93
103
|
|
|
94
104
|
### Known issues to fix
|
|
95
105
|
|
|
96
106
|
1. **Delivery enum mismatch** — npm v1.17.13 uses `"steer"/"queue"`, but upstream `dev` branch source also uses `"steer"/"queue"`. The local clone (`C:\Code\opencode`) has been modified to use `"immediate"/"deferred"` but this is NOT yet upstream. When upstream switches, update `_client.py:delivery="queue"` and `_async_client.py` to `"deferred"`. Run `scripts/check-upstream.py` to monitor.
|
|
97
107
|
|
|
98
|
-
2. ~~**Config format** — `Opencode(config={"model": "anthropic/..."})` fails because config expects `provider.{id}.options.apiKey` format.~~ **
|
|
108
|
+
2. ~~**Config format** — `Opencode(config={"model": "anthropic/..."})` fails because config expects `provider.{id}.options.apiKey` format.~~ **FIXED**: `opencode(model=...)` no longer puts model in server config — passes it per-request.
|
|
99
109
|
|
|
100
|
-
3. **`v2_session_wait` broken** — `POST /api/session/{sessionID}/wait` returns "Session wait is not available yet" in v1.17.13. **FIXED**: `Session.prompt()` now polls `v2_session_context()` until an assistant message appears
|
|
110
|
+
3. **`v2_session_wait` broken** — `POST /api/session/{sessionID}/wait` returns "Session wait is not available yet" in v1.17.13. **FIXED**: `Session.prompt()` now polls `v2_session_context()` until an assistant message appears.
|
|
101
111
|
|
|
102
|
-
4. ~~**No async support** — `OpencodeClient` is sync-only
|
|
112
|
+
4. ~~**No async support** — `OpencodeClient` is sync-only.~~ **DONE**: Full async support.
|
|
103
113
|
|
|
104
114
|
5. **Streaming** — `ask_stream()` reads SSE events via `/event` but delta format may differ between server versions.
|
|
105
115
|
|
|
106
|
-
6. ~~**No upstream monitoring
|
|
116
|
+
6. ~~**No upstream monitoring**~~ **DONE**: `scripts/check-upstream.py` fetches upstream.
|
|
107
117
|
|
|
108
118
|
## Architecture
|
|
109
119
|
|
|
@@ -280,6 +290,44 @@ python web/server.py
|
|
|
280
290
|
### Step G: Upstream monitoring ✅ DONE
|
|
281
291
|
1. `scripts/check-upstream.py` checks delivery enum + structured output ✅
|
|
282
292
|
|
|
293
|
+
## Next Steps
|
|
294
|
+
|
|
295
|
+
### Step H: Complete typed model coverage
|
|
296
|
+
1. Add `cast_to` to remaining client methods (vcs, config, project, etc.)
|
|
297
|
+
2. Add `with_raw_response` pattern for raw HTTP access
|
|
298
|
+
3. Consider `model_construct()` for faster deserialization (skip validation)
|
|
299
|
+
|
|
300
|
+
### Step I: Release v0.2.0
|
|
301
|
+
1. Bump version in `pyproject.toml` to `0.2.0`
|
|
302
|
+
2. Publish to PyPI via Trusted Publishing
|
|
303
|
+
|
|
304
|
+
## Release Process
|
|
305
|
+
|
|
306
|
+
Run `python scripts/check-release.py` to check if a new PyPI release is needed.
|
|
307
|
+
The script compares the version in `pyproject.toml` with the latest git tag
|
|
308
|
+
and reports unreleased commits.
|
|
309
|
+
|
|
310
|
+
**Release checklist:**
|
|
311
|
+
- [ ] `python scripts/check-release.py -v` — confirms release is due
|
|
312
|
+
- [ ] `git log --oneline v0.2.0..HEAD` — review unreleased changes
|
|
313
|
+
- [ ] Version bumped in `pyproject.toml`
|
|
314
|
+
- [ ] CI green on master
|
|
315
|
+
- [ ] `python -m build && twine check dist/*` — wheel is valid
|
|
316
|
+
|
|
317
|
+
**Proactive behavior**:
|
|
318
|
+
- At the start of each session, I will run `python scripts/check-release.py`
|
|
319
|
+
automatically and alert you if a release is due (commits since last tag
|
|
320
|
+
without version bump).
|
|
321
|
+
- **Before every commit**, I will check if the staged changes include anything
|
|
322
|
+
"user-facing" (feat, fix, refactor, or dependency changes — anything beyond
|
|
323
|
+
chore/docs/style). If there has been no version bump since the last tagged
|
|
324
|
+
release, I will warn you and ask whether to bump the version before
|
|
325
|
+
committing.
|
|
326
|
+
|
|
327
|
+
### Step J: Compare with official SDK
|
|
328
|
+
1. Evaluate `opencode-ai` (official Stainless SDK) for low-level layer
|
|
329
|
+
2. Consider using their client as base with our high-level wrapper
|
|
330
|
+
|
|
283
331
|
## Style Guide
|
|
284
332
|
|
|
285
333
|
- Keep in one function unless composable/reusable
|
|
@@ -288,7 +336,7 @@ python web/server.py
|
|
|
288
336
|
- Prefer httpx over urllib/requests (HTTP client), except for `_binary.py` which uses `urllib.request` for download (stdlib, no extra deps)
|
|
289
337
|
- Method naming: snake_case, category prefix (e.g., `v2_session_*`, `file_*`, `config_*`)
|
|
290
338
|
- Type hints everywhere
|
|
291
|
-
- Avoid `Any` where possible — use
|
|
339
|
+
- Avoid `Any` where possible — use Pydantic models from `_response_models.py`
|
|
292
340
|
|
|
293
341
|
## Commit Convention
|
|
294
342
|
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## v0.1.1 (2026-07-03)
|
|
4
|
+
|
|
5
|
+
- chore: add keywords to pyproject.toml and .gitattributes
|
|
6
|
+
- docs: add badges to README and MIT license file
|
|
7
|
+
- feat(tests): add Docker smoke test for clean-machine scenario
|
|
8
|
+
- chore: use importlib.metadata for `__version__`
|
|
9
|
+
- chore: bump version to 0.1.1 for author/URLs fix
|
|
10
|
+
- fix(publish): set author to Sergey Kislyakov, fix URLs
|
|
11
|
+
|
|
12
|
+
## v0.1.0 (2026-06-30)
|
|
13
|
+
|
|
14
|
+
- feat: initial Python SDK for Opencode
|
|
15
|
+
- fix: resolve npm .cmd wrappers to real .exe binary on Windows
|
|
16
|
+
- fix(session): use V1 sync prompt with model support instead of V2
|
|
17
|
+
- feat(sdk): add keep parameter for multi-turn conversations
|
|
18
|
+
- feat(sdk): add auto_tools mode with ToolExecutor and permissions
|
|
19
|
+
- feat(web): add zero-dependency web UI with proxy server
|
|
20
|
+
- feat(async): add AsyncOpendcodeClient, AsyncSession, AsyncOpendcode
|
|
21
|
+
- feat(stream): add live_streaming.py, SSE streaming via ask_stream
|
|
22
|
+
- feat(sdk): add async_opencode, structured output, check-upstream
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Contributor Covenant Code of Conduct
|
|
2
|
+
|
|
3
|
+
## Our Pledge
|
|
4
|
+
|
|
5
|
+
We as members, contributors, and leaders pledge to make participation in our
|
|
6
|
+
community a harassment-free experience for everyone, regardless of age, body
|
|
7
|
+
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
|
8
|
+
identity and expression, level of experience, education, socio-economic status,
|
|
9
|
+
nationality, personal appearance, race, caste, color, religion, or sexual
|
|
10
|
+
identity and orientation.
|
|
11
|
+
|
|
12
|
+
We pledge to act and interact in ways that contribute to an open, welcoming,
|
|
13
|
+
diverse, inclusive, and healthy community.
|
|
14
|
+
|
|
15
|
+
## Our Standards
|
|
16
|
+
|
|
17
|
+
Examples of behavior that contributes to a positive environment:
|
|
18
|
+
|
|
19
|
+
* Demonstrating empathy and kindness toward other people
|
|
20
|
+
* Being respectful of differing opinions, viewpoints, and experiences
|
|
21
|
+
* Giving and gracefully accepting constructive feedback
|
|
22
|
+
* Accepting responsibility and apologizing to those affected by our mistakes,
|
|
23
|
+
and learning from the experience
|
|
24
|
+
* Focusing on what is best not just for us as individuals, but for the overall
|
|
25
|
+
community
|
|
26
|
+
|
|
27
|
+
Examples of unacceptable behavior:
|
|
28
|
+
|
|
29
|
+
* The use of sexualized language or imagery, and sexual attention or advances
|
|
30
|
+
of any kind
|
|
31
|
+
* Trolling, insulting or derogatory comments, and personal or political attacks
|
|
32
|
+
* Public or private harassment
|
|
33
|
+
* Publishing others' private information, such as a physical or email address,
|
|
34
|
+
without their explicit permission
|
|
35
|
+
* Other conduct which could reasonably be considered inappropriate in a
|
|
36
|
+
professional setting
|
|
37
|
+
|
|
38
|
+
## Enforcement Responsibilities
|
|
39
|
+
|
|
40
|
+
Community leaders are responsible for clarifying and enforcing our standards of
|
|
41
|
+
acceptable behavior and will take appropriate and fair corrective action in
|
|
42
|
+
response to any behavior that they deem inappropriate, threatening, offensive,
|
|
43
|
+
or harmful.
|
|
44
|
+
|
|
45
|
+
## Scope
|
|
46
|
+
|
|
47
|
+
This Code of Conduct applies within all community spaces, and also applies when
|
|
48
|
+
an individual is officially representing the community in public spaces.
|
|
49
|
+
|
|
50
|
+
## Enforcement
|
|
51
|
+
|
|
52
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
|
53
|
+
reported to the community leaders responsible for enforcement at
|
|
54
|
+
**s.kislyakov84@gmail.com**. All complaints will be reviewed and investigated
|
|
55
|
+
promptly and fairly.
|
|
56
|
+
|
|
57
|
+
## Attribution
|
|
58
|
+
|
|
59
|
+
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
|
60
|
+
version 2.1, available at
|
|
61
|
+
https://www.contributor-covenant.org/version/2/1/code_of_conduct.html.
|
|
62
|
+
|
|
63
|
+
[homepage]: https://www.contributor-covenant.org
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
## Development setup
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
pip install -e ".[dev]"
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Code style
|
|
10
|
+
|
|
11
|
+
- Type hints everywhere
|
|
12
|
+
- Avoid `Any` where possible — use `TypedDict` from `_models.py`
|
|
13
|
+
- Avoid single-use helper functions
|
|
14
|
+
- Prefer httpx over urllib/requests
|
|
15
|
+
- Method naming: snake_case with category prefix (e.g., `v2_session_*`, `file_*`)
|
|
16
|
+
- No comments unless absolutely necessary
|
|
17
|
+
|
|
18
|
+
## Testing
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
# Unit tests (no server needed)
|
|
22
|
+
pytest tests/ -v
|
|
23
|
+
|
|
24
|
+
# Live integration test (requires opencode in PATH)
|
|
25
|
+
python test_live.py
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Commit convention
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
type(scope): summary
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Types: `feat`, `fix`, `docs`, `chore`, `refactor`, `test`
|
|
35
|
+
|
|
36
|
+
## Pre-commit checks
|
|
37
|
+
|
|
38
|
+
Before committing, run:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
ruff check .
|
|
42
|
+
mypy src/
|
|
43
|
+
pytest tests/ -v
|
|
44
|
+
```
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Sergey Kislyakov
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -1,5 +1,51 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: opencode-py
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Python SDK for Opencode — the open source AI coding agent
|
|
5
|
+
Project-URL: Homepage, https://github.com/skislyakow/opencode-py
|
|
6
|
+
Project-URL: Repository, https://github.com/skislyakow/opencode-py
|
|
7
|
+
Project-URL: Documentation, https://github.com/skislyakow/opencode-py
|
|
8
|
+
Project-URL: Changelog, https://github.com/skislyakow/opencode-py/blob/main/CHANGELOG.md
|
|
9
|
+
Author-email: Sergey Kislyakov <s.kislyakov84@gmail.com>
|
|
10
|
+
License: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: ai,coding-agent,llm,opencode,python-sdk,sdk
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Requires-Python: >=3.10
|
|
23
|
+
Requires-Dist: httpx>=0.27.0
|
|
24
|
+
Requires-Dist: pydantic>=2.0.0
|
|
25
|
+
Requires-Dist: typing-extensions>=4.6.0
|
|
26
|
+
Provides-Extra: dev
|
|
27
|
+
Requires-Dist: build>=1.0; extra == 'dev'
|
|
28
|
+
Requires-Dist: httpx>=0.27.0; extra == 'dev'
|
|
29
|
+
Requires-Dist: mypy>=1.10.0; extra == 'dev'
|
|
30
|
+
Requires-Dist: pytest-asyncio>=0.21; extra == 'dev'
|
|
31
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
32
|
+
Requires-Dist: ruff>=0.5.0; extra == 'dev'
|
|
33
|
+
Requires-Dist: twine>=4.0; extra == 'dev'
|
|
34
|
+
Description-Content-Type: text/markdown
|
|
35
|
+
|
|
1
36
|
# Opencode Python SDK
|
|
2
37
|
|
|
38
|
+
<p align="center">
|
|
39
|
+
<a href="https://pypi.org/project/opencode-py/"><img src="https://img.shields.io/pypi/v/opencode-py" alt="PyPI version"></a>
|
|
40
|
+
<a href="https://pypi.org/project/opencode-py/"><img src="https://img.shields.io/pypi/pyversions/opencode-py" alt="Python versions"></a>
|
|
41
|
+
<a href="https://github.com/skislyakow/opencode-py/blob/main/LICENSE"><img src="https://img.shields.io/pypi/l/opencode-py" alt="License"></a>
|
|
42
|
+
<a href="https://pypi.org/project/opencode-py/"><img src="https://img.shields.io/pypi/dm/opencode-py" alt="Downloads"></a>
|
|
43
|
+
<a href="https://github.com/skislyakow/opencode-py/actions/workflows/test.yml"><img src="https://github.com/skislyakow/opencode-py/actions/workflows/test.yml/badge.svg" alt="Tests"></a>
|
|
44
|
+
<img src="https://img.shields.io/badge/build-hatchling-4051b5" alt="Hatchling">
|
|
45
|
+
<img src="https://img.shields.io/badge/http-httpx-blue" alt="httpx">
|
|
46
|
+
<img src="https://img.shields.io/badge/models-pydantic-E92063" alt="pydantic">
|
|
47
|
+
</p>
|
|
48
|
+
|
|
3
49
|
Python SDK for [Opencode](https://opencode.ai) — the open source AI coding agent.
|
|
4
50
|
|
|
5
51
|
```bash
|
|
@@ -88,9 +134,35 @@ with Opencode() as ai:
|
|
|
88
134
|
diff = ai.client.vcs_diff("HEAD~3")
|
|
89
135
|
config = ai.client.config_get()
|
|
90
136
|
session = ai.client.session_create()
|
|
91
|
-
ai.client.v2_session_prompt(session
|
|
137
|
+
ai.client.v2_session_prompt(session.id, {"text": "Hello"})
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
All client methods return typed Pydantic models — IDE autocomplete, validation, `.model_dump()`, `.model_dump_json()`.
|
|
141
|
+
|
|
142
|
+
### Retry & error handling
|
|
143
|
+
|
|
144
|
+
```python
|
|
145
|
+
from opencode import OpencodeClient, RateLimitError, InternalServerError
|
|
146
|
+
|
|
147
|
+
client = OpencodeClient(max_retries=3) # exponential backoff with jitter
|
|
148
|
+
|
|
149
|
+
try:
|
|
150
|
+
health = client.health()
|
|
151
|
+
print(health.version)
|
|
152
|
+
except RateLimitError:
|
|
153
|
+
print("too many requests — retried but failed")
|
|
154
|
+
except InternalServerError:
|
|
155
|
+
print("server error")
|
|
92
156
|
```
|
|
93
157
|
|
|
158
|
+
### Debug logging
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
OPENCODE_LOG=debug python my_script.py
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Shows all HTTP requests/responses with timing.
|
|
165
|
+
|
|
94
166
|
### Web UI (zero dependencies)
|
|
95
167
|
|
|
96
168
|
```bash
|
|
@@ -157,7 +229,7 @@ from opencode import AsyncOpendcodeClient
|
|
|
157
229
|
|
|
158
230
|
async with AsyncOpendcodeClient() as client:
|
|
159
231
|
health = await client.health()
|
|
160
|
-
print(health)
|
|
232
|
+
print(health.version) # typed Pydantic model
|
|
161
233
|
```
|
|
162
234
|
|
|
163
235
|
## Development
|
|
@@ -1,32 +1,16 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: opencode-py
|
|
3
|
-
Version: 0.1.0
|
|
4
|
-
Summary: Python SDK for Opencode — the open source AI coding agent
|
|
5
|
-
Project-URL: Homepage, https://opencode.ai
|
|
6
|
-
Project-URL: Repository, https://github.com/anomalyco/opencode
|
|
7
|
-
Project-URL: Documentation, https://opencode.ai/docs
|
|
8
|
-
Author-email: Anomaly <hello@opencode.ai>
|
|
9
|
-
License: MIT
|
|
10
|
-
Classifier: Development Status :: 4 - Beta
|
|
11
|
-
Classifier: Intended Audience :: Developers
|
|
12
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
-
Classifier: Programming Language :: Python :: 3
|
|
14
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
-
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
-
Requires-Python: >=3.10
|
|
19
|
-
Requires-Dist: httpx>=0.27.0
|
|
20
|
-
Provides-Extra: dev
|
|
21
|
-
Requires-Dist: build>=1.0; extra == 'dev'
|
|
22
|
-
Requires-Dist: httpx>=0.27.0; extra == 'dev'
|
|
23
|
-
Requires-Dist: pytest-asyncio>=0.21; extra == 'dev'
|
|
24
|
-
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
25
|
-
Requires-Dist: twine>=4.0; extra == 'dev'
|
|
26
|
-
Description-Content-Type: text/markdown
|
|
27
|
-
|
|
28
1
|
# Opencode Python SDK
|
|
29
2
|
|
|
3
|
+
<p align="center">
|
|
4
|
+
<a href="https://pypi.org/project/opencode-py/"><img src="https://img.shields.io/pypi/v/opencode-py" alt="PyPI version"></a>
|
|
5
|
+
<a href="https://pypi.org/project/opencode-py/"><img src="https://img.shields.io/pypi/pyversions/opencode-py" alt="Python versions"></a>
|
|
6
|
+
<a href="https://github.com/skislyakow/opencode-py/blob/main/LICENSE"><img src="https://img.shields.io/pypi/l/opencode-py" alt="License"></a>
|
|
7
|
+
<a href="https://pypi.org/project/opencode-py/"><img src="https://img.shields.io/pypi/dm/opencode-py" alt="Downloads"></a>
|
|
8
|
+
<a href="https://github.com/skislyakow/opencode-py/actions/workflows/test.yml"><img src="https://github.com/skislyakow/opencode-py/actions/workflows/test.yml/badge.svg" alt="Tests"></a>
|
|
9
|
+
<img src="https://img.shields.io/badge/build-hatchling-4051b5" alt="Hatchling">
|
|
10
|
+
<img src="https://img.shields.io/badge/http-httpx-blue" alt="httpx">
|
|
11
|
+
<img src="https://img.shields.io/badge/models-pydantic-E92063" alt="pydantic">
|
|
12
|
+
</p>
|
|
13
|
+
|
|
30
14
|
Python SDK for [Opencode](https://opencode.ai) — the open source AI coding agent.
|
|
31
15
|
|
|
32
16
|
```bash
|
|
@@ -115,9 +99,35 @@ with Opencode() as ai:
|
|
|
115
99
|
diff = ai.client.vcs_diff("HEAD~3")
|
|
116
100
|
config = ai.client.config_get()
|
|
117
101
|
session = ai.client.session_create()
|
|
118
|
-
ai.client.v2_session_prompt(session
|
|
102
|
+
ai.client.v2_session_prompt(session.id, {"text": "Hello"})
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
All client methods return typed Pydantic models — IDE autocomplete, validation, `.model_dump()`, `.model_dump_json()`.
|
|
106
|
+
|
|
107
|
+
### Retry & error handling
|
|
108
|
+
|
|
109
|
+
```python
|
|
110
|
+
from opencode import OpencodeClient, RateLimitError, InternalServerError
|
|
111
|
+
|
|
112
|
+
client = OpencodeClient(max_retries=3) # exponential backoff with jitter
|
|
113
|
+
|
|
114
|
+
try:
|
|
115
|
+
health = client.health()
|
|
116
|
+
print(health.version)
|
|
117
|
+
except RateLimitError:
|
|
118
|
+
print("too many requests — retried but failed")
|
|
119
|
+
except InternalServerError:
|
|
120
|
+
print("server error")
|
|
119
121
|
```
|
|
120
122
|
|
|
123
|
+
### Debug logging
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
OPENCODE_LOG=debug python my_script.py
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Shows all HTTP requests/responses with timing.
|
|
130
|
+
|
|
121
131
|
### Web UI (zero dependencies)
|
|
122
132
|
|
|
123
133
|
```bash
|
|
@@ -184,7 +194,7 @@ from opencode import AsyncOpendcodeClient
|
|
|
184
194
|
|
|
185
195
|
async with AsyncOpendcodeClient() as client:
|
|
186
196
|
health = await client.health()
|
|
187
|
-
print(health)
|
|
197
|
+
print(health.version) # typed Pydantic model
|
|
188
198
|
```
|
|
189
199
|
|
|
190
200
|
## Development
|