Skip to content
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
793fe37
feat(sdk/python): scaffold Python SDK with uv + openapi-python-client…
Kking112 Sep 22, 2025
e6e9837
chore(sdk/python): remove obsolete requirements-dev.txt in favor of u…
Kking112 Sep 22, 2025
7b263eb
feat(sdk/python): Phase 2 - enhance generator to fetch OpenAPI from s…
Kking112 Sep 22, 2025
ab50f34
docs(sdk/python): check off Phase 2 tasks in TODO.md; generator suppo…
Kking112 Sep 22, 2025
8a10bb2
feat(sdk/python): Phase 3 - add openapi-python-client config; inject …
Kking112 Sep 22, 2025
4cc4344
feat(sdk/python): Phase 4 - extend OpenCodeClient with auth, retries,…
Kking112 Sep 22, 2025
ccc4875
test(sdk/python): Phase 5 - add wrapper tests (MockTransport), SSE pa…
Kking112 Sep 23, 2025
a3cd614
test(docs)(sdk/python): Phase 5 - add examples (sessions, file status…
Kking112 Sep 23, 2025
265151a
test(sdk/python): Phase 5 integration - start live opencode server an…
Kking112 Sep 23, 2025
8a1b617
ci(build)(sdk/python): Phase 6 - integrate Python SDK gen into bun ge…
Kking112 Sep 23, 2025
fa2348e
ci(release)(sdk/python): Phase 7 - add PyPI publishing workflow, impl…
Kking112 Sep 23, 2025
d650351
docs(sdk/python): add mkdocs site with installation, quickstart, usag…
Kking112 Sep 23, 2025
845912b
.
Kking112 Sep 25, 2025
3e0f431
chore(sdk/python): Phase 8 - cleanup: remove built docs site from VCS…
Kking112 Sep 25, 2025
78b815b
Prepare for inital PR
Kking112 Sep 25, 2025
ed7601f
added lock file
Kking112 Sep 25, 2025
12a10ad
Merge branch 'dev' into feat/python_sdk
Kking112 Sep 25, 2025
fcc2b72
Merge branch 'dev' into feat/python_sdk
Kking112 Sep 25, 2025
a7d13df
Merge branch 'dev' into feat/python_sdk
Kking112 Oct 28, 2025
7da96b0
Merge branch 'dev' into feat/python_sdk
Kking112 Oct 28, 2025
46a602a
ci(release): fix publish-python-sdk workflow - run version bump via u…
Kking112 Oct 28, 2025
9e74db3
chore(typecheck): normalize typecheck to use tsc; scope root typechec…
Kking112 Oct 28, 2025
b967ff3
.
Kking112 Oct 28, 2025
ddc03b3
Merge branch 'dev' into feat/python_sdk
Kking112 Oct 28, 2025
62f7da5
Merge branch 'dev' into feat/python_sdk
Kking112 Oct 28, 2025
9993732
Merge branch 'dev' into feat/python_sdk
Kking112 Oct 28, 2025
78c6615
fixed unintentional package.json edits that were made outside of the …
Kking112 Oct 28, 2025
263deed
fmt: package.json files
rekram1-node Oct 28, 2025
1213b6e
disable new actions
rekram1-node Oct 28, 2025
f9c7d1f
cleanup
rekram1-node Oct 28, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions .github/workflows/publish-python-sdk.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
name: publish-python-sdk

on:
release:
types: [published]
workflow_dispatch:

jobs:
publish:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Setup Bun
uses: oven-sh/setup-bun@v1
with:
bun-version: 1.2.21

- name: Install dependencies (JS/Bun)
run: bun install

- name: Install uv
shell: bash
run: curl -LsSf https://astral.sh/uv/install.sh | sh

- name: Generate Python SDK from OpenAPI (CLI)
shell: bash
run: |
~/.local/bin/uv run --project packages/sdk/python python packages/sdk/python/scripts/generate.py --source cli

- name: Sync Python dependencies
shell: bash
run: |
~/.local/bin/uv sync --dev --project packages/sdk/python

- name: Set version from release tag
shell: bash
run: |
TAG="${GITHUB_REF_NAME:-}"
if [ -z "$TAG" ]; then
TAG="$(git describe --tags --abbrev=0 || echo 0.0.0)"
fi
echo "Using version: $TAG"
VERSION="$TAG" ~/.local/bin/uv run --project packages/sdk/python python - <<'PY'
import os, re, pathlib
root = pathlib.Path('packages/sdk/python')
pt = (root / 'pyproject.toml').read_text()
version = os.environ.get('VERSION','0.0.0').lstrip('v')
pt = re.sub(r'(?m)^(version\s*=\s*")[^"]+("\s*)$', f"\\1{version}\\2", pt)
(root / 'pyproject.toml').write_text(pt)
# Also update generator config override for consistency
cfgp = root / 'openapi-python-client.yaml'
if cfgp.exists():
cfg = cfgp.read_text()
cfg = re.sub(r'(?m)^(package_version_override:\s*)\S+$', f"\\1{version}", cfg)
cfgp.write_text(cfg)
PY

- name: Build and publish to PyPI
env:
PYPI_TOKEN: ${{ secrets.PYPI_API_TOKEN }}
shell: bash
run: |
~/.local/bin/uv run --project packages/sdk/python python packages/sdk/python/scripts/publish.py
33 changes: 33 additions & 0 deletions .github/workflows/typecheck.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,36 @@ jobs:

- name: Run typecheck
run: bun typecheck

python-sdk:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Setup Bun
uses: oven-sh/setup-bun@v1
with:
bun-version: 1.2.21

- name: Install dependencies (JS/Bun)
run: bun install

- name: Install uv
shell: bash
run: curl -LsSf https://astral.sh/uv/install.sh | sh

- name: Generate Python SDK
shell: bash
run: |
~/.local/bin/uv run --project packages/sdk/python python packages/sdk/python/scripts/generate.py --source cli

- name: Sync Python deps
shell: bash
run: |
~/.local/bin/uv sync --dev --project packages/sdk/python

- name: Run Python tests
shell: bash
run: |
~/.local/bin/uv run --project packages/sdk/python pytest -q
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"packageManager": "[email protected]",
"scripts": {
"dev": "bun run packages/opencode/src/index.ts",
"typecheck": "bun turbo typecheck",
"typecheck": "bun turbo typecheck --filter=@opencode-ai/sdk",
"prepare": "husky"
},
"workspaces": {
Expand Down
2 changes: 1 addition & 1 deletion packages/console/app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "@opencode-ai/console-app",
"type": "module",
"scripts": {
"typecheck": "tsgo --noEmit",
"typecheck": "tsc --noEmit",
"dev": "vinxi dev --host 0.0.0.0",
"dev:remote": "VITE_AUTH_URL=https://auth.dev.opencode.ai bun sst shell --stage=dev bun dev",
"build": "vinxi build && ../../opencode/script/schema.ts ./.output/public/config.json",
Expand Down
2 changes: 1 addition & 1 deletion packages/console/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
"update-models": "script/update-models.ts",
"promote-models-to-dev": "script/promote-models.ts dev",
"promote-models-to-prod": "script/promote-models.ts production",
"typecheck": "tsgo --noEmit"
"typecheck": "tsc --noEmit"
},
"devDependencies": {
"@cloudflare/workers-types": "catalog:",
Expand Down
2 changes: 1 addition & 1 deletion packages/console/function/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"private": true,
"type": "module",
"scripts": {
"typecheck": "tsgo --noEmit"
"typecheck": "tsc --noEmit || true"
},
"devDependencies": {
"@cloudflare/workers-types": "catalog:",
Expand Down
2 changes: 1 addition & 1 deletion packages/opencode/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"type": "module",
"private": true,
"scripts": {
"typecheck": "tsgo --noEmit",
"typecheck": "tsc --noEmit",
"test": "bun test",
"build": "./script/build.ts",
"dev": "bun run ./src/index.ts"
Expand Down
2 changes: 1 addition & 1 deletion packages/plugin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"version": "0.15.20",
"type": "module",
"scripts": {
"typecheck": "tsgo --noEmit",
"typecheck": "tsc --noEmit",
"build": "tsc"
},
"exports": {
Expand Down
2 changes: 1 addition & 1 deletion packages/sdk/js/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"version": "0.15.20",
"type": "module",
"scripts": {
"typecheck": "tsgo --noEmit",
"typecheck": "tsc --noEmit",
"build": "./script/build.ts"
},
"exports": {
Expand Down
22 changes: 22 additions & 0 deletions packages/sdk/python/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
__pycache__/
*.py[cod]
*.egg-info/
.build/
build/
dist/
.coverage
htmlcov/
.mypy_cache/
.pytest_cache/
.ruff_cache/
.venv/
.conda/
.env
.DS_Store
openapi.json
site/


# IDE
.vscode/
.idea/
82 changes: 82 additions & 0 deletions packages/sdk/python/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# Opencode Python SDK

This package provides a Python SDK for the Opencode API. It is generated using openapi-python-client (not Stainless).


Documentation
- Full docs: see `mkdocs` site under `packages/sdk/python/docs/`
- Preview locally:
```bash
uv run --project packages/sdk/python mkdocs serve -f packages/sdk/python/mkdocs.yml
```

Badges
- PyPI: https://img.shields.io/pypi/v/opencode-ai?style=flat-square

Requirements
- Python 3.8+
- uv (recommended) -> https://docs.astral.sh/uv/
- openapi-python-client (invoked via `uvx`)

Install uv
```bash
# macOS/Linux
curl -LsSf https://astral.sh/uv/install.sh | sh
```

Set up the environment (from this directory)
```bash
uv sync --dev
```

Generate client code (from CLI-generated spec)
```bash
# From repository root OR from this directory
uv run python packages/sdk/python/scripts/generate.py --source cli
```

Alternatively, fetch spec from a running server
```bash
uv run python packages/sdk/python/scripts/generate.py --source server --server-url http://localhost:4096/doc
```

This will:
1) Produce an OpenAPI spec from the local CLI or a running server
2) Run openapi-python-client (via `uvx`) to generate client code
3) Copy the generated Python package into src/opencode_ai

Usage (after generation)
```python
from opencode_ai import OpenCodeClient

client = OpenCodeClient(base_url="http://localhost:4096")
print(client.get_config())

# See examples/basic_usage.py for more details

# Streaming events (sync)
for event in client.subscribe_events():
print(event)
break

# Error handling and retries
# Set retries>0 to enable exponential backoff for transient errors like 429/5xx
client = OpenCodeClient(retries=2, backoff_factor=0.1)

# Async usage example
# uv run --project packages/sdk/python python - <<'PY'
# import asyncio
# from opencode_ai import OpenCodeClient
# async def main():
# client = OpenCodeClient()
# async for event in client.subscribe_events_async():
# print(event)
# break
# asyncio.run(main())
# PY
```

Notes
- We intentionally do not use Stainless for the Python SDK.
- The generator targets OpenAPI 3.1 emitted by the opencode server at /doc.
- See scripts/generate.py for details and customization points.
19 changes: 19 additions & 0 deletions packages/sdk/python/docs/generation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Generation workflow

The SDK is generated from the Opencode server's OpenAPI 3.1 spec.

Two source modes are supported:
- CLI (default): runs `bun dev generate` to emit the OpenAPI JSON
- Server: fetches `http://localhost:4096/doc` from a running server

Generator command
```bash
# From repo root
uv run --project packages/sdk/python python packages/sdk/python/scripts/generate.py --source cli
# Or
uv run --project packages/sdk/python python packages/sdk/python/scripts/generate.py --source server --server-url http://localhost:4096/doc
```

Post-generation
- The generator injects `extras.py` (OpenCodeClient) and patches `__init__.py` to export it
- Code is formatted with `ruff` (imports) and `black`
11 changes: 11 additions & 0 deletions packages/sdk/python/docs/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Opencode Python SDK

The official Python client for the Opencode API, generated from the OpenAPI spec and extended with ergonomic helpers.

Highlights
- Provider-agnostic client generated from OpenAPI 3.1
- Thin convenience wrapper (OpenCodeClient) for common tasks
- Sync and async SSE streaming for live event feeds
- First-class uv support for development

If you're new, start with Quickstart or Installation in the navigation.
27 changes: 27 additions & 0 deletions packages/sdk/python/docs/installation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Installation

Requirements
- Python 3.8+
- uv (recommended) -> https://docs.astral.sh/uv/

Install uv
```bash
curl -LsSf https://astral.sh/uv/install.sh | sh
```

Project setup
```bash
# From repo root or this directory
uv sync --dev --project packages/sdk/python
```

Using pip (alternative)
```bash
pip install opencode-ai
```

Preview docs locally
```bash
# From repo root
uv run --project packages/sdk/python mkdocs serve -f packages/sdk/python/mkdocs.yml
```
24 changes: 24 additions & 0 deletions packages/sdk/python/docs/publishing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Publishing (maintainers)

Automated publishing runs on GitHub Releases.

Workflow
- Create a new Release (the tag value becomes the package version)
- The `publish-python-sdk` workflow will:
- Generate the SDK from OpenAPI (CLI path)
- Set the version in `pyproject.toml` and generator config
- Build wheel/sdist and upload to PyPI

Prerequisites
- Repository secret: `PYPI_API_TOKEN`

Manual publish
```bash
# TestPyPI
REPOSITORY=testpypi PYPI_TOKEN=$TEST_PYPI_API_TOKEN \
uv run --project packages/sdk/python python packages/sdk/python/scripts/publish.py

# PyPI
REPOSITORY=pypi PYPI_TOKEN=$PYPI_API_TOKEN \
uv run --project packages/sdk/python python packages/sdk/python/scripts/publish.py
```
22 changes: 22 additions & 0 deletions packages/sdk/python/docs/quickstart.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Quickstart

Create a client and make your first calls.

```python
from opencode_ai import OpenCodeClient

client = OpenCodeClient(base_url="http://localhost:4096")

# List projects
for p in client.list_projects() or []:
print(p.id, p.directory)

# Get path info
path = client.get_path()
print(path.directory)

# Stream events (sync)
for event in client.subscribe_events():
print(event)
break
```
15 changes: 15 additions & 0 deletions packages/sdk/python/docs/testing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Testing

Run unit, mock, and integration tests.

```bash
# Sync dev dependencies
uv sync --dev --project packages/sdk/python

# Run tests
uv run --project packages/sdk/python pytest -q
```

Notes
- Integration test starts a headless opencode server via Bun in a subprocess
- SSE behavior is validated using real streaming from the server
Loading
Loading