opencode-python-sdk 0.0.1.dev1__py3-none-any.whl

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 (62) hide show
  1. opencode/.generated.json +39 -0
  2. opencode/__init__.py +221 -0
  3. opencode/_base_client.py +539 -0
  4. opencode/_client.py +255 -0
  5. opencode/_constants.py +27 -0
  6. opencode/_errors.py +547 -0
  7. opencode/_events.py +732 -0
  8. opencode/_exceptions.py +271 -0
  9. opencode/_models.py +54 -0
  10. opencode/_pagination.py +192 -0
  11. opencode/_pty.py +586 -0
  12. opencode/_qs.py +95 -0
  13. opencode/_resource.py +42 -0
  14. opencode/_rpc.py +489 -0
  15. opencode/_server.py +335 -0
  16. opencode/_streaming.py +248 -0
  17. opencode/_types.py +77 -0
  18. opencode/_unions.py +46 -0
  19. opencode/_version.py +8 -0
  20. opencode/lib/__init__.py +5 -0
  21. opencode/lib/_ready.py +91 -0
  22. opencode/lib/_session.py +231 -0
  23. opencode/py.typed +0 -0
  24. opencode/resources/__init__.py +364 -0
  25. opencode/resources/agent.py +179 -0
  26. opencode/resources/command.py +100 -0
  27. opencode/resources/config.py +240 -0
  28. opencode/resources/credential.py +384 -0
  29. opencode/resources/debug.py +178 -0
  30. opencode/resources/event.py +88 -0
  31. opencode/resources/experimental.py +765 -0
  32. opencode/resources/file.py +355 -0
  33. opencode/resources/form.py +100 -0
  34. opencode/resources/generate.py +110 -0
  35. opencode/resources/integration.py +1033 -0
  36. opencode/resources/location.py +162 -0
  37. opencode/resources/mcp.py +492 -0
  38. opencode/resources/message.py +152 -0
  39. opencode/resources/migration.py +118 -0
  40. opencode/resources/model.py +177 -0
  41. opencode/resources/permission.py +704 -0
  42. opencode/resources/plugin.py +250 -0
  43. opencode/resources/project.py +187 -0
  44. opencode/resources/provider.py +183 -0
  45. opencode/resources/pty.py +522 -0
  46. opencode/resources/reference.py +100 -0
  47. opencode/resources/rpc.py +113 -0
  48. opencode/resources/server.py +230 -0
  49. opencode/resources/session.py +3567 -0
  50. opencode/resources/shell.py +412 -0
  51. opencode/resources/skill.py +100 -0
  52. opencode/resources/vcs.py +500 -0
  53. opencode/resources/voice.py +113 -0
  54. opencode/resources/websearch.py +184 -0
  55. opencode/resources/worktree.py +336 -0
  56. opencode/testing.py +508 -0
  57. opencode/types/__init__.py +1462 -0
  58. opencode/types/_generated.py +8540 -0
  59. opencode_python_sdk-0.0.1.dev1.dist-info/METADATA +468 -0
  60. opencode_python_sdk-0.0.1.dev1.dist-info/RECORD +62 -0
  61. opencode_python_sdk-0.0.1.dev1.dist-info/WHEEL +4 -0
  62. opencode_python_sdk-0.0.1.dev1.dist-info/licenses/LICENSE +21 -0
opencode/_client.py ADDED
@@ -0,0 +1,255 @@
1
+ from __future__ import annotations
2
+
3
+ from functools import cached_property
4
+ from typing import TYPE_CHECKING, Any
5
+
6
+ from typing_extensions import Self
7
+
8
+ from ._base_client import AsyncAPIClient, SyncAPIClient
9
+ from ._constants import DEFAULT_MAX_RETRIES, DEFAULT_TIMEOUT, DEFAULT_USERNAME
10
+ from ._events import AsyncEventHub, EventHub
11
+ from ._rpc import AsyncTypedRpcResource, TypedRpcResource
12
+ from ._types import NOT_GIVEN, NotGiven, Timeout
13
+ from .resources import AsyncResources, SyncResources
14
+
15
+ if TYPE_CHECKING:
16
+ import os
17
+ from collections.abc import Iterable, Mapping
18
+
19
+ import httpx
20
+
21
+ from .testing import FakeServer
22
+
23
+ __all__ = ["AsyncOpencode", "Opencode"]
24
+
25
+ FAKE_BASE_URL = "http://opencode.fake"
26
+ """Base URL of clients made by ``Opencode.fake()``."""
27
+
28
+
29
+ class Opencode(SyncAPIClient, SyncResources):
30
+ """Synchronous client for an OpenCode server.
31
+
32
+ Args:
33
+ base_url: Server URL, for example ``http://127.0.0.1:4096``. Defaults to ``OPENCODE_BASE_URL``.
34
+ password: Server password. Defaults to ``OPENCODE_PASSWORD``, then ``OPENCODE_SERVER_PASSWORD``. Pass ``""``
35
+ to send no credentials.
36
+ username: Basic auth user name. The OpenCode server uses ``opencode``.
37
+ directory: Default project directory. Sent as the ``location`` of every request that accepts one, unless
38
+ the call passes its own ``location``.
39
+ timeout: Default timeout in seconds, or an ``httpx.Timeout``. Event streams only apply the connect timeout.
40
+ max_retries: Retries for connection failures and transient statuses. Requests that may have changed state
41
+ on the server are only retried when the server refused them before acting (429 and 503).
42
+ default_headers: Headers sent with every request.
43
+ default_query: Query parameters sent with every request.
44
+ http_client: A preconfigured ``httpx.Client`` (proxies, custom transports, event hooks). The caller keeps
45
+ ownership and must close it.
46
+ transport: An ``httpx`` transport for the client's own connection pool, such as
47
+ :class:`opencode.testing.FakeServer`. Cannot be combined with ``http_client``.
48
+
49
+ Example::
50
+
51
+ from opencode import Opencode
52
+
53
+ with Opencode("http://127.0.0.1:4096", password="...") as client:
54
+ for agent in client.agent.list():
55
+ print(agent.id)
56
+ """
57
+
58
+ def __init__(
59
+ self,
60
+ base_url: str | httpx.URL | None = None,
61
+ *,
62
+ password: str | None = None,
63
+ username: str = DEFAULT_USERNAME,
64
+ directory: str | os.PathLike[str] | None = None,
65
+ timeout: Timeout = DEFAULT_TIMEOUT,
66
+ max_retries: int = DEFAULT_MAX_RETRIES,
67
+ default_headers: Mapping[str, str] | None = None,
68
+ default_query: Mapping[str, object] | None = None,
69
+ http_client: httpx.Client | None = None,
70
+ transport: httpx.BaseTransport | None = None,
71
+ ) -> None:
72
+ super().__init__(
73
+ base_url=base_url,
74
+ password=password,
75
+ username=username,
76
+ directory=directory,
77
+ timeout=timeout,
78
+ max_retries=max_retries,
79
+ default_headers=default_headers,
80
+ default_query=default_query,
81
+ http_client=http_client,
82
+ transport=transport,
83
+ )
84
+
85
+ @cached_property
86
+ def events(self) -> EventHub:
87
+ """The shared event stream: one connection for every subscriber. See :class:`opencode.EventHub`."""
88
+ return EventHub(self)
89
+
90
+ @cached_property
91
+ def rpc(self) -> TypedRpcResource:
92
+ """Plugin RPC calls: ``client.rpc.call(...)``, or ``client.rpc(Definition)`` for typed access."""
93
+ return TypedRpcResource(self)
94
+
95
+ @classmethod
96
+ def fake(cls, server: FakeServer | None = None, **kwargs: Any) -> Self:
97
+ """Returns a client wired to an in-process :class:`opencode.testing.FakeServer`, for tests.
98
+
99
+ Pass your own ``server`` to configure replies and inspect requests; other arguments go to the constructor.
100
+ """
101
+ from .testing import FakeServer
102
+
103
+ kwargs.setdefault("password", "")
104
+ return cls(FAKE_BASE_URL, transport=server if server is not None else FakeServer(), **kwargs)
105
+
106
+ def wait_until_ready(
107
+ self, *, agents: Iterable[str] = (), mcp_servers: Iterable[str] = (), timeout: float = 60
108
+ ) -> None:
109
+ """Blocks until the server answers, the named ``agents`` are listed and the named ``mcp_servers`` are
110
+ connected.
111
+
112
+ Agents load asynchronously after the server starts, so call this before creating sessions on a freshly
113
+ booted server. Connection errors and 503s while the server boots count as not ready yet.
114
+
115
+ Raises:
116
+ TimeoutError: Something was still missing after ``timeout`` seconds. The message names it.
117
+ """
118
+ from .lib._ready import wait_until_ready
119
+
120
+ wait_until_ready(self, agents=agents, mcp_servers=mcp_servers, timeout=timeout)
121
+
122
+ def with_options(
123
+ self,
124
+ *,
125
+ base_url: str | httpx.URL | None = None,
126
+ password: str | NotGiven | None = NOT_GIVEN,
127
+ directory: str | os.PathLike[str] | NotGiven | None = NOT_GIVEN,
128
+ timeout: Timeout | NotGiven = NOT_GIVEN,
129
+ max_retries: int | None = None,
130
+ default_headers: Mapping[str, str] | None = None,
131
+ default_query: Mapping[str, object] | None = None,
132
+ ) -> Self:
133
+ """Returns a client with some options changed. It shares this client's connection pool.
134
+
135
+ ``default_headers`` and ``default_query`` are merged over the current values.
136
+ """
137
+ client = type(self)(
138
+ base_url=base_url or self.base_url,
139
+ password=self.password or "" if isinstance(password, NotGiven) else password,
140
+ username=self.username,
141
+ directory=self.directory if isinstance(directory, NotGiven) else directory,
142
+ timeout=self.timeout if isinstance(timeout, NotGiven) else timeout,
143
+ max_retries=self.max_retries if max_retries is None else max_retries,
144
+ default_headers={**self._default_headers, **(default_headers or {})},
145
+ default_query={**self._default_query, **(default_query or {})},
146
+ http_client=self._http,
147
+ )
148
+ return client
149
+
150
+
151
+ class AsyncOpencode(AsyncAPIClient, AsyncResources):
152
+ """Asynchronous client for an OpenCode server. Works with asyncio and trio.
153
+
154
+ Takes the same arguments as :class:`Opencode`; ``http_client`` is an ``httpx.AsyncClient``.
155
+
156
+ Example::
157
+
158
+ from opencode import AsyncOpencode
159
+
160
+ async with AsyncOpencode("http://127.0.0.1:4096", password="...") as client:
161
+ for agent in await client.agent.list():
162
+ print(agent.id)
163
+ """
164
+
165
+ def __init__(
166
+ self,
167
+ base_url: str | httpx.URL | None = None,
168
+ *,
169
+ password: str | None = None,
170
+ username: str = DEFAULT_USERNAME,
171
+ directory: str | os.PathLike[str] | None = None,
172
+ timeout: Timeout = DEFAULT_TIMEOUT,
173
+ max_retries: int = DEFAULT_MAX_RETRIES,
174
+ default_headers: Mapping[str, str] | None = None,
175
+ default_query: Mapping[str, object] | None = None,
176
+ http_client: httpx.AsyncClient | None = None,
177
+ transport: httpx.AsyncBaseTransport | None = None,
178
+ ) -> None:
179
+ super().__init__(
180
+ base_url=base_url,
181
+ password=password,
182
+ username=username,
183
+ directory=directory,
184
+ timeout=timeout,
185
+ max_retries=max_retries,
186
+ default_headers=default_headers,
187
+ default_query=default_query,
188
+ http_client=http_client,
189
+ transport=transport,
190
+ )
191
+
192
+ @cached_property
193
+ def events(self) -> AsyncEventHub:
194
+ """The shared event stream: one connection for every subscriber. See :class:`opencode.AsyncEventHub`."""
195
+ return AsyncEventHub(self)
196
+
197
+ @cached_property
198
+ def rpc(self) -> AsyncTypedRpcResource:
199
+ """Plugin RPC calls: ``client.rpc.call(...)``, or ``client.rpc(Definition)`` for typed access."""
200
+ return AsyncTypedRpcResource(self)
201
+
202
+ @classmethod
203
+ def fake(cls, server: FakeServer | None = None, **kwargs: Any) -> Self:
204
+ """Returns a client wired to an in-process :class:`opencode.testing.FakeServer`, for tests.
205
+
206
+ Pass your own ``server`` to configure replies and inspect requests; other arguments go to the constructor.
207
+ """
208
+ from .testing import FakeServer
209
+
210
+ kwargs.setdefault("password", "")
211
+ return cls(FAKE_BASE_URL, transport=server if server is not None else FakeServer(), **kwargs)
212
+
213
+ async def wait_until_ready(
214
+ self, *, agents: Iterable[str] = (), mcp_servers: Iterable[str] = (), timeout: float = 60
215
+ ) -> None:
216
+ """Blocks until the server answers, the named ``agents`` are listed and the named ``mcp_servers`` are
217
+ connected.
218
+
219
+ Agents load asynchronously after the server starts, so call this before creating sessions on a freshly
220
+ booted server. Connection errors and 503s while the server boots count as not ready yet.
221
+
222
+ Raises:
223
+ TimeoutError: Something was still missing after ``timeout`` seconds. The message names it.
224
+ """
225
+ from .lib._ready import async_wait_until_ready
226
+
227
+ await async_wait_until_ready(self, agents=agents, mcp_servers=mcp_servers, timeout=timeout)
228
+
229
+ def with_options(
230
+ self,
231
+ *,
232
+ base_url: str | httpx.URL | None = None,
233
+ password: str | NotGiven | None = NOT_GIVEN,
234
+ directory: str | os.PathLike[str] | NotGiven | None = NOT_GIVEN,
235
+ timeout: Timeout | NotGiven = NOT_GIVEN,
236
+ max_retries: int | None = None,
237
+ default_headers: Mapping[str, str] | None = None,
238
+ default_query: Mapping[str, object] | None = None,
239
+ ) -> Self:
240
+ """Returns a client with some options changed. It shares this client's connection pool.
241
+
242
+ ``default_headers`` and ``default_query`` are merged over the current values.
243
+ """
244
+ client = type(self)(
245
+ base_url=base_url or self.base_url,
246
+ password=self.password or "" if isinstance(password, NotGiven) else password,
247
+ username=self.username,
248
+ directory=self.directory if isinstance(directory, NotGiven) else directory,
249
+ timeout=self.timeout if isinstance(timeout, NotGiven) else timeout,
250
+ max_retries=self.max_retries if max_retries is None else max_retries,
251
+ default_headers={**self._default_headers, **(default_headers or {})},
252
+ default_query={**self._default_query, **(default_query or {})},
253
+ http_client=self._http,
254
+ )
255
+ return client
opencode/_constants.py ADDED
@@ -0,0 +1,27 @@
1
+ from __future__ import annotations
2
+
3
+ import httpx
4
+
5
+ DEFAULT_TIMEOUT = httpx.Timeout(timeout=600.0, connect=10.0)
6
+ """Ten minutes overall with a ten second connect timeout. Agent operations can run for a long time."""
7
+
8
+ DEFAULT_MAX_RETRIES = 2
9
+ INITIAL_RETRY_DELAY = 0.5
10
+ MAX_RETRY_DELAY = 8.0
11
+ MAX_RETRY_AFTER = 60.0
12
+ """A ``Retry-After`` above this many seconds is not honored; the request fails instead of stalling."""
13
+
14
+ DEFAULT_CONNECTION_LIMITS = httpx.Limits(max_connections=100, max_keepalive_connections=20, keepalive_expiry=30.0)
15
+
16
+ DEFAULT_USERNAME = "opencode"
17
+ """The Basic auth user name the OpenCode server expects."""
18
+
19
+ BASE_URL_ENV = "OPENCODE_BASE_URL"
20
+ PASSWORD_ENVS = ("OPENCODE_PASSWORD", "OPENCODE_SERVER_PASSWORD")
21
+ """Password variables, in the order the OpenCode CLI reads them."""
22
+
23
+ IDEMPOTENT_METHODS = frozenset({"GET", "HEAD", "OPTIONS", "PUT", "DELETE"})
24
+ RETRYABLE_STATUSES = frozenset({408, 429, 500, 502, 503, 504})
25
+ """Statuses retried for idempotent requests."""
26
+ RETRYABLE_STATUSES_UNSAFE = frozenset({429, 503})
27
+ """Statuses retried for non-idempotent requests: the server refused the request before acting on it."""