opencode-py 0.2.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.
- {opencode_py-0.2.0 → opencode_py-0.2.1}/PKG-INFO +1 -1
- {opencode_py-0.2.0 → opencode_py-0.2.1}/pyproject.toml +2 -2
- {opencode_py-0.2.0 → opencode_py-0.2.1}/scripts/check-release.py +95 -95
- {opencode_py-0.2.0 → opencode_py-0.2.1}/src/opencode/__main__.py +3 -2
- {opencode_py-0.2.0 → opencode_py-0.2.1}/src/opencode/_errors.py +94 -94
- {opencode_py-0.2.0 → opencode_py-0.2.1}/src/opencode/_response_models.py +242 -242
- {opencode_py-0.2.0 → opencode_py-0.2.1}/web/index.html +199 -199
- {opencode_py-0.2.0 → opencode_py-0.2.1}/.editorconfig +0 -0
- {opencode_py-0.2.0 → opencode_py-0.2.1}/.gitattributes +0 -0
- {opencode_py-0.2.0 → opencode_py-0.2.1}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {opencode_py-0.2.0 → opencode_py-0.2.1}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {opencode_py-0.2.0 → opencode_py-0.2.1}/.github/workflows/publish.yml +0 -0
- {opencode_py-0.2.0 → opencode_py-0.2.1}/.github/workflows/test.yml +0 -0
- {opencode_py-0.2.0 → opencode_py-0.2.1}/.gitignore +0 -0
- {opencode_py-0.2.0 → opencode_py-0.2.1}/.pre-commit-config.yaml +0 -0
- {opencode_py-0.2.0 → opencode_py-0.2.1}/AGENTS.md +0 -0
- {opencode_py-0.2.0 → opencode_py-0.2.1}/CHANGELOG.md +0 -0
- {opencode_py-0.2.0 → opencode_py-0.2.1}/CODE_OF_CONDUCT.md +0 -0
- {opencode_py-0.2.0 → opencode_py-0.2.1}/CONTRIBUTING.md +0 -0
- {opencode_py-0.2.0 → opencode_py-0.2.1}/LICENSE +0 -0
- {opencode_py-0.2.0 → opencode_py-0.2.1}/README.md +0 -0
- {opencode_py-0.2.0 → opencode_py-0.2.1}/README.ru.md +0 -0
- {opencode_py-0.2.0 → opencode_py-0.2.1}/RELEASE.md +0 -0
- {opencode_py-0.2.0 → opencode_py-0.2.1}/SECURITY.md +0 -0
- {opencode_py-0.2.0 → opencode_py-0.2.1}/demo.py +0 -0
- {opencode_py-0.2.0 → opencode_py-0.2.1}/docs/opencode-docs-ru.md +0 -0
- {opencode_py-0.2.0 → opencode_py-0.2.1}/live.py +0 -0
- {opencode_py-0.2.0 → opencode_py-0.2.1}/live_async.py +0 -0
- {opencode_py-0.2.0 → opencode_py-0.2.1}/live_streaming.py +0 -0
- {opencode_py-0.2.0 → opencode_py-0.2.1}/scripts/check-upstream.py +0 -0
- {opencode_py-0.2.0 → opencode_py-0.2.1}/src/opencode/__init__.py +0 -0
- {opencode_py-0.2.0 → opencode_py-0.2.1}/src/opencode/_async_client.py +0 -0
- {opencode_py-0.2.0 → opencode_py-0.2.1}/src/opencode/_async_opencode.py +0 -0
- {opencode_py-0.2.0 → opencode_py-0.2.1}/src/opencode/_async_session.py +0 -0
- {opencode_py-0.2.0 → opencode_py-0.2.1}/src/opencode/_binary.py +0 -0
- {opencode_py-0.2.0 → opencode_py-0.2.1}/src/opencode/_client.py +0 -0
- {opencode_py-0.2.0 → opencode_py-0.2.1}/src/opencode/_logs.py +0 -0
- {opencode_py-0.2.0 → opencode_py-0.2.1}/src/opencode/_models.py +0 -0
- {opencode_py-0.2.0 → opencode_py-0.2.1}/src/opencode/_opencode.py +0 -0
- {opencode_py-0.2.0 → opencode_py-0.2.1}/src/opencode/_process.py +0 -0
- {opencode_py-0.2.0 → opencode_py-0.2.1}/src/opencode/_server.py +0 -0
- {opencode_py-0.2.0 → opencode_py-0.2.1}/src/opencode/_session.py +0 -0
- {opencode_py-0.2.0 → opencode_py-0.2.1}/src/opencode/_tools.py +0 -0
- {opencode_py-0.2.0 → opencode_py-0.2.1}/src/opencode/_types.py +0 -0
- {opencode_py-0.2.0 → opencode_py-0.2.1}/src/opencode/py.typed +0 -0
- {opencode_py-0.2.0 → opencode_py-0.2.1}/test_all.py +0 -0
- {opencode_py-0.2.0 → opencode_py-0.2.1}/test_live.py +0 -0
- {opencode_py-0.2.0 → opencode_py-0.2.1}/tests/docker/Dockerfile +0 -0
- {opencode_py-0.2.0 → opencode_py-0.2.1}/tests/docker/test_smoke.py +0 -0
- {opencode_py-0.2.0 → opencode_py-0.2.1}/tests/test_async_client.py +0 -0
- {opencode_py-0.2.0 → opencode_py-0.2.1}/tests/test_client.py +0 -0
- {opencode_py-0.2.0 → opencode_py-0.2.1}/tests/test_opencode.py +0 -0
- {opencode_py-0.2.0 → opencode_py-0.2.1}/web/server.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: opencode-py
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: Python SDK for Opencode — the open source AI coding agent
|
|
5
5
|
Project-URL: Homepage, https://github.com/skislyakow/opencode-py
|
|
6
6
|
Project-URL: Repository, https://github.com/skislyakow/opencode-py
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "opencode-py"
|
|
3
|
-
version = "0.2.
|
|
3
|
+
version = "0.2.1"
|
|
4
4
|
description = "Python SDK for Opencode — the open source AI coding agent"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
long_description_content_type = "text/markdown"
|
|
@@ -45,7 +45,7 @@ Documentation = "https://github.com/skislyakow/opencode-py"
|
|
|
45
45
|
Changelog = "https://github.com/skislyakow/opencode-py/blob/main/CHANGELOG.md"
|
|
46
46
|
|
|
47
47
|
[project.scripts]
|
|
48
|
-
opencode = "opencode.__main__:main"
|
|
48
|
+
opencode-py = "opencode.__main__:main"
|
|
49
49
|
|
|
50
50
|
[build-system]
|
|
51
51
|
requires = ["hatchling"]
|
|
@@ -1,95 +1,95 @@
|
|
|
1
|
-
"""Check if a new PyPI release is needed.
|
|
2
|
-
|
|
3
|
-
Compares the version in pyproject.toml with the latest git tag.
|
|
4
|
-
Exits with code 0 if no release needed, 1 if a release is recommended.
|
|
5
|
-
|
|
6
|
-
Usage:
|
|
7
|
-
python scripts/check-release.py
|
|
8
|
-
python scripts/check-release.py --verbose
|
|
9
|
-
"""
|
|
10
|
-
|
|
11
|
-
from __future__ import annotations
|
|
12
|
-
|
|
13
|
-
import re
|
|
14
|
-
import subprocess
|
|
15
|
-
import sys
|
|
16
|
-
from pathlib import Path
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
def get_current_version() -> str:
|
|
20
|
-
pyproject = Path(__file__).parent.parent / "pyproject.toml"
|
|
21
|
-
text = pyproject.read_text()
|
|
22
|
-
m = re.search(r'^version\s*=\s*"([^"]+)"', text, re.MULTILINE)
|
|
23
|
-
if m:
|
|
24
|
-
return m.group(1)
|
|
25
|
-
raise RuntimeError("Could not find version in pyproject.toml")
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
def get_latest_tag() -> str | None:
|
|
29
|
-
result = subprocess.run(
|
|
30
|
-
["git", "tag", "--list", "v*", "--sort=-version:refname"],
|
|
31
|
-
capture_output=True, text=True, cwd=Path(__file__).parent.parent,
|
|
32
|
-
)
|
|
33
|
-
tags = [t.strip() for t in result.stdout.splitlines() if t.strip()]
|
|
34
|
-
return tags[0] if tags else None
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
def get_commit_count_since_tag(tag: str) -> int:
|
|
38
|
-
result = subprocess.run(
|
|
39
|
-
["git", "rev-list", f"{tag}..HEAD", "--count"],
|
|
40
|
-
capture_output=True, text=True, cwd=Path(__file__).parent.parent,
|
|
41
|
-
)
|
|
42
|
-
return int(result.stdout.strip() or "0")
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
def main() -> int:
|
|
46
|
-
verbose = "--verbose" in sys.argv or "-v" in sys.argv
|
|
47
|
-
|
|
48
|
-
current = get_current_version()
|
|
49
|
-
latest_tag = get_latest_tag()
|
|
50
|
-
|
|
51
|
-
print(f"Current version (pyproject.toml): {current}")
|
|
52
|
-
|
|
53
|
-
if latest_tag is None:
|
|
54
|
-
print("No git tags found — this would be the first release.")
|
|
55
|
-
return 0
|
|
56
|
-
|
|
57
|
-
tag_version = latest_tag.lstrip("v")
|
|
58
|
-
print(f"Latest git tag: {latest_tag}")
|
|
59
|
-
|
|
60
|
-
commits_since = get_commit_count_since_tag(latest_tag)
|
|
61
|
-
|
|
62
|
-
if current == tag_version:
|
|
63
|
-
if commits_since > 0:
|
|
64
|
-
print(f"\n==> {commits_since} commit(s) since {latest_tag}, "
|
|
65
|
-
f"but version hasn't been bumped ({current}).")
|
|
66
|
-
if verbose:
|
|
67
|
-
result = subprocess.run(
|
|
68
|
-
["git", "log", f"{latest_tag}..HEAD", "--oneline"],
|
|
69
|
-
capture_output=True, text=True,
|
|
70
|
-
cwd=Path(__file__).parent.parent,
|
|
71
|
-
)
|
|
72
|
-
print("\nUnreleased commits:")
|
|
73
|
-
for line in result.stdout.splitlines():
|
|
74
|
-
print(f" {line}")
|
|
75
|
-
print("\n=> Run `python -m build` and publish when ready:")
|
|
76
|
-
print(" python -m build")
|
|
77
|
-
print(" twine upload dist/*")
|
|
78
|
-
return 1
|
|
79
|
-
else:
|
|
80
|
-
print("\n[ok] Everything is up to date. No release needed.")
|
|
81
|
-
return 0
|
|
82
|
-
else:
|
|
83
|
-
print(f"\n=> Version in pyproject.toml ({current}) differs from "
|
|
84
|
-
f"latest tag ({tag_version}).")
|
|
85
|
-
print(" A new release may be ready to publish.")
|
|
86
|
-
if verbose:
|
|
87
|
-
print("\n To publish:")
|
|
88
|
-
print(" git tag v" + current)
|
|
89
|
-
print(" git push origin v" + current)
|
|
90
|
-
print(" python -m build && twine upload dist/*")
|
|
91
|
-
return 0
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
if __name__ == "__main__":
|
|
95
|
-
sys.exit(main())
|
|
1
|
+
"""Check if a new PyPI release is needed.
|
|
2
|
+
|
|
3
|
+
Compares the version in pyproject.toml with the latest git tag.
|
|
4
|
+
Exits with code 0 if no release needed, 1 if a release is recommended.
|
|
5
|
+
|
|
6
|
+
Usage:
|
|
7
|
+
python scripts/check-release.py
|
|
8
|
+
python scripts/check-release.py --verbose
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import re
|
|
14
|
+
import subprocess
|
|
15
|
+
import sys
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def get_current_version() -> str:
|
|
20
|
+
pyproject = Path(__file__).parent.parent / "pyproject.toml"
|
|
21
|
+
text = pyproject.read_text()
|
|
22
|
+
m = re.search(r'^version\s*=\s*"([^"]+)"', text, re.MULTILINE)
|
|
23
|
+
if m:
|
|
24
|
+
return m.group(1)
|
|
25
|
+
raise RuntimeError("Could not find version in pyproject.toml")
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def get_latest_tag() -> str | None:
|
|
29
|
+
result = subprocess.run(
|
|
30
|
+
["git", "tag", "--list", "v*", "--sort=-version:refname"],
|
|
31
|
+
capture_output=True, text=True, cwd=Path(__file__).parent.parent,
|
|
32
|
+
)
|
|
33
|
+
tags = [t.strip() for t in result.stdout.splitlines() if t.strip()]
|
|
34
|
+
return tags[0] if tags else None
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def get_commit_count_since_tag(tag: str) -> int:
|
|
38
|
+
result = subprocess.run(
|
|
39
|
+
["git", "rev-list", f"{tag}..HEAD", "--count"],
|
|
40
|
+
capture_output=True, text=True, cwd=Path(__file__).parent.parent,
|
|
41
|
+
)
|
|
42
|
+
return int(result.stdout.strip() or "0")
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def main() -> int:
|
|
46
|
+
verbose = "--verbose" in sys.argv or "-v" in sys.argv
|
|
47
|
+
|
|
48
|
+
current = get_current_version()
|
|
49
|
+
latest_tag = get_latest_tag()
|
|
50
|
+
|
|
51
|
+
print(f"Current version (pyproject.toml): {current}")
|
|
52
|
+
|
|
53
|
+
if latest_tag is None:
|
|
54
|
+
print("No git tags found — this would be the first release.")
|
|
55
|
+
return 0
|
|
56
|
+
|
|
57
|
+
tag_version = latest_tag.lstrip("v")
|
|
58
|
+
print(f"Latest git tag: {latest_tag}")
|
|
59
|
+
|
|
60
|
+
commits_since = get_commit_count_since_tag(latest_tag)
|
|
61
|
+
|
|
62
|
+
if current == tag_version:
|
|
63
|
+
if commits_since > 0:
|
|
64
|
+
print(f"\n==> {commits_since} commit(s) since {latest_tag}, "
|
|
65
|
+
f"but version hasn't been bumped ({current}).")
|
|
66
|
+
if verbose:
|
|
67
|
+
result = subprocess.run(
|
|
68
|
+
["git", "log", f"{latest_tag}..HEAD", "--oneline"],
|
|
69
|
+
capture_output=True, text=True,
|
|
70
|
+
cwd=Path(__file__).parent.parent,
|
|
71
|
+
)
|
|
72
|
+
print("\nUnreleased commits:")
|
|
73
|
+
for line in result.stdout.splitlines():
|
|
74
|
+
print(f" {line}")
|
|
75
|
+
print("\n=> Run `python -m build` and publish when ready:")
|
|
76
|
+
print(" python -m build")
|
|
77
|
+
print(" twine upload dist/*")
|
|
78
|
+
return 1
|
|
79
|
+
else:
|
|
80
|
+
print("\n[ok] Everything is up to date. No release needed.")
|
|
81
|
+
return 0
|
|
82
|
+
else:
|
|
83
|
+
print(f"\n=> Version in pyproject.toml ({current}) differs from "
|
|
84
|
+
f"latest tag ({tag_version}).")
|
|
85
|
+
print(" A new release may be ready to publish.")
|
|
86
|
+
if verbose:
|
|
87
|
+
print("\n To publish:")
|
|
88
|
+
print(" git tag v" + current)
|
|
89
|
+
print(" git push origin v" + current)
|
|
90
|
+
print(" python -m build && twine upload dist/*")
|
|
91
|
+
return 0
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
if __name__ == "__main__":
|
|
95
|
+
sys.exit(main())
|
|
@@ -8,8 +8,9 @@ from opencode import opencode
|
|
|
8
8
|
def main() -> None:
|
|
9
9
|
args = sys.argv[1:]
|
|
10
10
|
if not args:
|
|
11
|
-
print("Usage:
|
|
12
|
-
print(" or:
|
|
11
|
+
print("Usage: opencode-py <prompt>")
|
|
12
|
+
print(" or: python -m opencode <prompt>")
|
|
13
|
+
print(" or: echo 'question' | opencode-py")
|
|
13
14
|
sys.exit(1)
|
|
14
15
|
prompt = " ".join(args)
|
|
15
16
|
result = opencode(prompt)
|
|
@@ -1,94 +1,94 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from typing import Any
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class OpencodeError(Exception):
|
|
7
|
-
"""Base exception for all opencode SDK errors."""
|
|
8
|
-
|
|
9
|
-
def __init__(
|
|
10
|
-
self,
|
|
11
|
-
message: str = "",
|
|
12
|
-
*,
|
|
13
|
-
status: int | None = None,
|
|
14
|
-
body: object = None,
|
|
15
|
-
):
|
|
16
|
-
self.status = status
|
|
17
|
-
self.body = body
|
|
18
|
-
super().__init__(message)
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
class APIError(OpencodeError):
|
|
22
|
-
"""Base class for all API-related errors."""
|
|
23
|
-
|
|
24
|
-
def __init__(
|
|
25
|
-
self,
|
|
26
|
-
message: str = "",
|
|
27
|
-
*,
|
|
28
|
-
request: Any = None,
|
|
29
|
-
response: Any = None,
|
|
30
|
-
body: object = None,
|
|
31
|
-
status_code: int | None = None,
|
|
32
|
-
):
|
|
33
|
-
self.request = request
|
|
34
|
-
self.response = response
|
|
35
|
-
super().__init__(message, status=status_code, body=body)
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
class APIResponseValidationError(APIError):
|
|
39
|
-
"""Response data did not match the expected schema."""
|
|
40
|
-
|
|
41
|
-
def __init__(self, message: str = "", *, response: Any = None, body: object = None):
|
|
42
|
-
super().__init__(message, response=response, body=body)
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
class APIStatusError(APIError):
|
|
46
|
-
"""Base class for errors with an HTTP status code."""
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
class BadRequestError(APIStatusError):
|
|
50
|
-
"""HTTP 400"""
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
class AuthenticationError(APIStatusError):
|
|
54
|
-
"""HTTP 401"""
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
class PermissionDeniedError(APIStatusError):
|
|
58
|
-
"""HTTP 403"""
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
class NotFoundError(APIStatusError):
|
|
62
|
-
"""HTTP 404"""
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
class ConflictError(APIStatusError):
|
|
66
|
-
"""HTTP 409"""
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
class UnprocessableEntityError(APIStatusError):
|
|
70
|
-
"""HTTP 422"""
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
class RateLimitError(APIStatusError):
|
|
74
|
-
"""HTTP 429"""
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
class InternalServerError(APIStatusError):
|
|
78
|
-
"""HTTP 5xx"""
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
class APIConnectionError(APIError):
|
|
82
|
-
"""Connection or transport error."""
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
class APITimeoutError(APIConnectionError):
|
|
86
|
-
"""Request timed out."""
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
class BinaryNotFoundError(OpencodeError):
|
|
90
|
-
"""Opencode binary not found on the system."""
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
class ServerStartupTimeoutError(OpencodeError):
|
|
94
|
-
"""Server did not start within the expected timeout."""
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class OpencodeError(Exception):
|
|
7
|
+
"""Base exception for all opencode SDK errors."""
|
|
8
|
+
|
|
9
|
+
def __init__(
|
|
10
|
+
self,
|
|
11
|
+
message: str = "",
|
|
12
|
+
*,
|
|
13
|
+
status: int | None = None,
|
|
14
|
+
body: object = None,
|
|
15
|
+
):
|
|
16
|
+
self.status = status
|
|
17
|
+
self.body = body
|
|
18
|
+
super().__init__(message)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class APIError(OpencodeError):
|
|
22
|
+
"""Base class for all API-related errors."""
|
|
23
|
+
|
|
24
|
+
def __init__(
|
|
25
|
+
self,
|
|
26
|
+
message: str = "",
|
|
27
|
+
*,
|
|
28
|
+
request: Any = None,
|
|
29
|
+
response: Any = None,
|
|
30
|
+
body: object = None,
|
|
31
|
+
status_code: int | None = None,
|
|
32
|
+
):
|
|
33
|
+
self.request = request
|
|
34
|
+
self.response = response
|
|
35
|
+
super().__init__(message, status=status_code, body=body)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class APIResponseValidationError(APIError):
|
|
39
|
+
"""Response data did not match the expected schema."""
|
|
40
|
+
|
|
41
|
+
def __init__(self, message: str = "", *, response: Any = None, body: object = None):
|
|
42
|
+
super().__init__(message, response=response, body=body)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class APIStatusError(APIError):
|
|
46
|
+
"""Base class for errors with an HTTP status code."""
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class BadRequestError(APIStatusError):
|
|
50
|
+
"""HTTP 400"""
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class AuthenticationError(APIStatusError):
|
|
54
|
+
"""HTTP 401"""
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class PermissionDeniedError(APIStatusError):
|
|
58
|
+
"""HTTP 403"""
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class NotFoundError(APIStatusError):
|
|
62
|
+
"""HTTP 404"""
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class ConflictError(APIStatusError):
|
|
66
|
+
"""HTTP 409"""
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class UnprocessableEntityError(APIStatusError):
|
|
70
|
+
"""HTTP 422"""
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class RateLimitError(APIStatusError):
|
|
74
|
+
"""HTTP 429"""
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class InternalServerError(APIStatusError):
|
|
78
|
+
"""HTTP 5xx"""
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class APIConnectionError(APIError):
|
|
82
|
+
"""Connection or transport error."""
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
class APITimeoutError(APIConnectionError):
|
|
86
|
+
"""Request timed out."""
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
class BinaryNotFoundError(OpencodeError):
|
|
90
|
+
"""Opencode binary not found on the system."""
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
class ServerStartupTimeoutError(OpencodeError):
|
|
94
|
+
"""Server did not start within the expected timeout."""
|