opencode-py 0.1.0__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.
- opencode/__init__.py +45 -0
- opencode/__main__.py +20 -0
- opencode/_async_client.py +538 -0
- opencode/_async_opencode.py +255 -0
- opencode/_async_session.py +155 -0
- opencode/_binary.py +135 -0
- opencode/_client.py +532 -0
- opencode/_errors.py +20 -0
- opencode/_models.py +110 -0
- opencode/_opencode.py +290 -0
- opencode/_process.py +24 -0
- opencode/_server.py +97 -0
- opencode/_session.py +160 -0
- opencode/_tools.py +156 -0
- opencode_py-0.1.0.dist-info/METADATA +201 -0
- opencode_py-0.1.0.dist-info/RECORD +17 -0
- opencode_py-0.1.0.dist-info/WHEEL +4 -0
opencode/_client.py
ADDED
|
@@ -0,0 +1,532 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any, Dict, List, Optional, Sequence
|
|
4
|
+
|
|
5
|
+
import httpx
|
|
6
|
+
|
|
7
|
+
from opencode._errors import ApiError
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class OpencodeClient:
|
|
11
|
+
def __init__(
|
|
12
|
+
self,
|
|
13
|
+
*,
|
|
14
|
+
base_url: str = "http://127.0.0.1:4096",
|
|
15
|
+
directory: Optional[str] = None,
|
|
16
|
+
workspace: Optional[str] = None,
|
|
17
|
+
timeout: float = 300.0,
|
|
18
|
+
httpx_client: Optional[httpx.Client] = None,
|
|
19
|
+
):
|
|
20
|
+
self.base_url = base_url.rstrip("/")
|
|
21
|
+
self.directory = directory
|
|
22
|
+
self.workspace = workspace
|
|
23
|
+
self._client = httpx_client or httpx.Client(timeout=httpx.Timeout(timeout))
|
|
24
|
+
|
|
25
|
+
# ------------------------------------------------------------------
|
|
26
|
+
# Internal helpers
|
|
27
|
+
# ------------------------------------------------------------------
|
|
28
|
+
|
|
29
|
+
def _build_url(self, path: str) -> str:
|
|
30
|
+
return f"{self.base_url}{path}"
|
|
31
|
+
|
|
32
|
+
def _merge_params(
|
|
33
|
+
self,
|
|
34
|
+
params: Optional[Dict[str, Any]] = None,
|
|
35
|
+
) -> Dict[str, Any]:
|
|
36
|
+
params = dict(params or {})
|
|
37
|
+
if self.directory and "directory" not in params:
|
|
38
|
+
params["directory"] = self.directory
|
|
39
|
+
if self.workspace and "workspace" not in params:
|
|
40
|
+
params["workspace"] = self.workspace
|
|
41
|
+
return params
|
|
42
|
+
|
|
43
|
+
def _handle(self, response: httpx.Response) -> Any:
|
|
44
|
+
if response.is_success:
|
|
45
|
+
if response.status_code == 204:
|
|
46
|
+
return None
|
|
47
|
+
ct = response.headers.get("content-type", "")
|
|
48
|
+
if "text/event-stream" in ct:
|
|
49
|
+
return response
|
|
50
|
+
if "text/" in ct:
|
|
51
|
+
return response.text
|
|
52
|
+
return response.json()
|
|
53
|
+
body = None
|
|
54
|
+
try:
|
|
55
|
+
body = response.json()
|
|
56
|
+
except Exception:
|
|
57
|
+
body = response.text
|
|
58
|
+
message = None
|
|
59
|
+
if isinstance(body, dict):
|
|
60
|
+
message = body.get("message") or body.get("error") or str(body)
|
|
61
|
+
elif isinstance(body, str):
|
|
62
|
+
message = body
|
|
63
|
+
raise ApiError(
|
|
64
|
+
message or f"HTTP {response.status_code}: {response.reason_phrase}",
|
|
65
|
+
status=response.status_code,
|
|
66
|
+
body=body,
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
def _request(
|
|
70
|
+
self,
|
|
71
|
+
method: str,
|
|
72
|
+
path: str,
|
|
73
|
+
*,
|
|
74
|
+
params: Optional[Dict[str, Any]] = None,
|
|
75
|
+
json_body: Any = None,
|
|
76
|
+
headers: Optional[Dict[str, str]] = None,
|
|
77
|
+
) -> Any:
|
|
78
|
+
url = self._build_url(path)
|
|
79
|
+
params = self._merge_params(params)
|
|
80
|
+
hdrs = {"Content-Type": "application/json", **(headers or {})}
|
|
81
|
+
response = self._client.request(method, url, params=params, json=json_body, headers=hdrs)
|
|
82
|
+
return self._handle(response)
|
|
83
|
+
|
|
84
|
+
def _request_stream(
|
|
85
|
+
self,
|
|
86
|
+
method: str,
|
|
87
|
+
path: str,
|
|
88
|
+
*,
|
|
89
|
+
params: Optional[Dict[str, Any]] = None,
|
|
90
|
+
json_body: Any = None,
|
|
91
|
+
headers: Optional[Dict[str, str]] = None,
|
|
92
|
+
) -> httpx.Response:
|
|
93
|
+
url = self._build_url(path)
|
|
94
|
+
params = self._merge_params(params)
|
|
95
|
+
hdrs = {"Content-Type": "application/json", **(headers or {})}
|
|
96
|
+
request = self._client.build_request(method, url, params=params, json=json_body, headers=hdrs)
|
|
97
|
+
return self._client.send(request, stream=True)
|
|
98
|
+
|
|
99
|
+
# ------------------------------------------------------------------
|
|
100
|
+
# Global
|
|
101
|
+
# ------------------------------------------------------------------
|
|
102
|
+
|
|
103
|
+
def health(self) -> Any:
|
|
104
|
+
return self._request("GET", "/global/health")
|
|
105
|
+
|
|
106
|
+
def global_event(self) -> httpx.Response:
|
|
107
|
+
return self._request_stream("GET", "/global/event")
|
|
108
|
+
|
|
109
|
+
def global_dispose(self) -> Any:
|
|
110
|
+
return self._request("POST", "/global/dispose")
|
|
111
|
+
|
|
112
|
+
def global_upgrade(self, target: Optional[str] = None) -> Any:
|
|
113
|
+
return self._request("POST", "/global/upgrade", json_body={"target": target})
|
|
114
|
+
|
|
115
|
+
def global_config_get(self) -> Any:
|
|
116
|
+
return self._request("GET", "/global/config")
|
|
117
|
+
|
|
118
|
+
def global_config_update(self, config: Any) -> Any:
|
|
119
|
+
return self._request("PATCH", "/global/config", json_body={"config": config})
|
|
120
|
+
|
|
121
|
+
# ------------------------------------------------------------------
|
|
122
|
+
# Config
|
|
123
|
+
# ------------------------------------------------------------------
|
|
124
|
+
|
|
125
|
+
def config_get(self, **kwargs) -> Any:
|
|
126
|
+
return self._request("GET", "/config", params=kwargs)
|
|
127
|
+
|
|
128
|
+
def config_update(self, config: Any, **kwargs) -> Any:
|
|
129
|
+
return self._request("PATCH", "/config", json_body={"config": config}, params=kwargs)
|
|
130
|
+
|
|
131
|
+
def config_providers(self, **kwargs) -> Any:
|
|
132
|
+
return self._request("GET", "/config/providers", params=kwargs)
|
|
133
|
+
|
|
134
|
+
# ------------------------------------------------------------------
|
|
135
|
+
# Session
|
|
136
|
+
# ------------------------------------------------------------------
|
|
137
|
+
|
|
138
|
+
def session_create(self, **kwargs) -> Any:
|
|
139
|
+
return self._request("POST", "/session", json_body=kwargs or None)
|
|
140
|
+
|
|
141
|
+
def session_get(self, session_id: str) -> Any:
|
|
142
|
+
return self._request("GET", f"/session/{session_id}")
|
|
143
|
+
|
|
144
|
+
def session_list(self, **kwargs) -> Any:
|
|
145
|
+
return self._request("GET", "/session", params=kwargs)
|
|
146
|
+
|
|
147
|
+
def session_delete(self, session_id: str) -> Any:
|
|
148
|
+
return self._request("DELETE", f"/session/{session_id}")
|
|
149
|
+
|
|
150
|
+
def session_update(self, session_id: str, **kwargs) -> Any:
|
|
151
|
+
return self._request("PUT", f"/session/{session_id}", json_body=kwargs or None)
|
|
152
|
+
|
|
153
|
+
def session_messages(self, session_id: str, **kwargs) -> Any:
|
|
154
|
+
return self._request("GET", f"/session/{session_id}/message", params=kwargs)
|
|
155
|
+
|
|
156
|
+
def session_message(self, session_id: str, message_id: str) -> Any:
|
|
157
|
+
return self._request("GET", f"/session/{session_id}/message/{message_id}")
|
|
158
|
+
|
|
159
|
+
def session_fork(self, session_id: str, **kwargs) -> Any:
|
|
160
|
+
return self._request("POST", f"/session/{session_id}/fork", json_body=kwargs or None)
|
|
161
|
+
|
|
162
|
+
def session_abort(self, session_id: str) -> Any:
|
|
163
|
+
return self._request("POST", f"/session/{session_id}/abort")
|
|
164
|
+
|
|
165
|
+
def session_init(self, session_id: str, **kwargs) -> Any:
|
|
166
|
+
return self._request("POST", f"/session/{session_id}/init", json_body=kwargs or None)
|
|
167
|
+
|
|
168
|
+
def session_summarize(self, session_id: str) -> Any:
|
|
169
|
+
return self._request("POST", f"/session/{session_id}/summarize")
|
|
170
|
+
|
|
171
|
+
def session_todo(self, session_id: str) -> Any:
|
|
172
|
+
return self._request("GET", f"/session/{session_id}/todo")
|
|
173
|
+
|
|
174
|
+
def session_children(self, session_id: str) -> Any:
|
|
175
|
+
return self._request("GET", f"/session/{session_id}/child")
|
|
176
|
+
|
|
177
|
+
def session_diff(self, session_id: str) -> Any:
|
|
178
|
+
return self._request("GET", f"/session/{session_id}/diff")
|
|
179
|
+
|
|
180
|
+
def session_share(self, session_id: str) -> Any:
|
|
181
|
+
return self._request("POST", f"/session/{session_id}/share")
|
|
182
|
+
|
|
183
|
+
def session_unshare(self, session_id: str) -> Any:
|
|
184
|
+
return self._request("DELETE", f"/session/{session_id}/share")
|
|
185
|
+
|
|
186
|
+
def session_revert(self, session_id: str) -> Any:
|
|
187
|
+
return self._request("POST", f"/session/{session_id}/revert")
|
|
188
|
+
|
|
189
|
+
def session_unrevert(self, session_id: str) -> Any:
|
|
190
|
+
return self._request("POST", f"/session/{session_id}/unrevert")
|
|
191
|
+
|
|
192
|
+
def session_command(self, session_id: str, command: str, **kwargs) -> Any:
|
|
193
|
+
return self._request("POST", f"/session/{session_id}/command", json_body={"command": command, **kwargs})
|
|
194
|
+
|
|
195
|
+
def session_shell(self, session_id: str, command: str) -> Any:
|
|
196
|
+
return self._request("POST", f"/session/{session_id}/shell", json_body={"command": command})
|
|
197
|
+
|
|
198
|
+
# ------------------------------------------------------------------
|
|
199
|
+
# V2 Session
|
|
200
|
+
# ------------------------------------------------------------------
|
|
201
|
+
|
|
202
|
+
def v2_session_list(self, **kwargs) -> Any:
|
|
203
|
+
return self._request("GET", "/api/session", params=kwargs)
|
|
204
|
+
|
|
205
|
+
def session_send(self, session_id: str, body: Any) -> Any:
|
|
206
|
+
return self._request("POST", f"/session/{session_id}/message", json_body=body)
|
|
207
|
+
|
|
208
|
+
def v2_session_prompt(self, session_id: str, prompt: Any, *, delivery: str = "queue", **kwargs) -> Any:
|
|
209
|
+
body: Dict[str, Any] = {"prompt": prompt, "delivery": delivery, **kwargs}
|
|
210
|
+
return self._request("POST", f"/api/session/{session_id}/prompt", json_body=body)
|
|
211
|
+
|
|
212
|
+
def v2_session_wait(self, session_id: str) -> Any:
|
|
213
|
+
return self._request("POST", f"/api/session/{session_id}/wait")
|
|
214
|
+
|
|
215
|
+
def v2_session_context(self, session_id: str, **kwargs) -> Any:
|
|
216
|
+
return self._request("GET", f"/api/session/{session_id}/context", params=kwargs)
|
|
217
|
+
|
|
218
|
+
def v2_session_messages(self, session_id: str, **kwargs) -> Any:
|
|
219
|
+
return self._request("GET", f"/api/session/{session_id}/message", params=kwargs)
|
|
220
|
+
|
|
221
|
+
def v2_session_compact(self, session_id: str) -> Any:
|
|
222
|
+
return self._request("POST", f"/api/session/{session_id}/compact")
|
|
223
|
+
|
|
224
|
+
def v2_model_list(self, **kwargs) -> Any:
|
|
225
|
+
return self._request("GET", "/api/model", params=kwargs)
|
|
226
|
+
|
|
227
|
+
def v2_provider_list(self, **kwargs) -> Any:
|
|
228
|
+
return self._request("GET", "/api/provider", params=kwargs)
|
|
229
|
+
|
|
230
|
+
def v2_provider_get(self, provider_id: str) -> Any:
|
|
231
|
+
return self._request("GET", f"/api/provider/{provider_id}")
|
|
232
|
+
|
|
233
|
+
# ------------------------------------------------------------------
|
|
234
|
+
# Auth
|
|
235
|
+
# ------------------------------------------------------------------
|
|
236
|
+
|
|
237
|
+
def auth_set(self, provider_id: str, auth: Any) -> Any:
|
|
238
|
+
return self._request("PUT", f"/auth/{provider_id}", json_body={"auth": auth})
|
|
239
|
+
|
|
240
|
+
def auth_remove(self, provider_id: str) -> Any:
|
|
241
|
+
return self._request("DELETE", f"/auth/{provider_id}")
|
|
242
|
+
|
|
243
|
+
# ------------------------------------------------------------------
|
|
244
|
+
# App
|
|
245
|
+
# ------------------------------------------------------------------
|
|
246
|
+
|
|
247
|
+
def app_log(self, **kwargs) -> Any:
|
|
248
|
+
return self._request("POST", "/log", json_body=kwargs or None)
|
|
249
|
+
|
|
250
|
+
def app_agents(self, **kwargs) -> Any:
|
|
251
|
+
return self._request("GET", "/agent", params=kwargs)
|
|
252
|
+
|
|
253
|
+
# ------------------------------------------------------------------
|
|
254
|
+
# File
|
|
255
|
+
# ------------------------------------------------------------------
|
|
256
|
+
|
|
257
|
+
def file_read(self, path: str, **kwargs) -> Any:
|
|
258
|
+
return self._request("GET", "/file/content", params={"path": path, **kwargs})
|
|
259
|
+
|
|
260
|
+
def file_list(self, path: str, **kwargs) -> Any:
|
|
261
|
+
return self._request("GET", "/file", params={"path": path, **kwargs})
|
|
262
|
+
|
|
263
|
+
def file_status(self, **kwargs) -> Any:
|
|
264
|
+
return self._request("GET", "/file/status", params=kwargs)
|
|
265
|
+
|
|
266
|
+
# ------------------------------------------------------------------
|
|
267
|
+
# Find
|
|
268
|
+
# ------------------------------------------------------------------
|
|
269
|
+
|
|
270
|
+
def find_text(self, pattern: str, **kwargs) -> Any:
|
|
271
|
+
return self._request("GET", "/find", params={"pattern": pattern, **kwargs})
|
|
272
|
+
|
|
273
|
+
def find_files(self, query: str, **kwargs) -> Any:
|
|
274
|
+
return self._request("GET", "/find/file", params={"query": query, **kwargs})
|
|
275
|
+
|
|
276
|
+
def find_symbols(self, query: str, **kwargs) -> Any:
|
|
277
|
+
return self._request("GET", "/find/symbol", params={"query": query, **kwargs})
|
|
278
|
+
|
|
279
|
+
# ------------------------------------------------------------------
|
|
280
|
+
# VCS
|
|
281
|
+
# ------------------------------------------------------------------
|
|
282
|
+
|
|
283
|
+
def vcs_get(self, **kwargs) -> Any:
|
|
284
|
+
return self._request("GET", "/vcs", params=kwargs)
|
|
285
|
+
|
|
286
|
+
def vcs_status(self, **kwargs) -> Any:
|
|
287
|
+
return self._request("GET", "/vcs/status", params=kwargs)
|
|
288
|
+
|
|
289
|
+
def vcs_diff(self, mode: str = "git", **kwargs) -> Any:
|
|
290
|
+
return self._request("GET", "/vcs/diff", params={"mode": mode, **kwargs})
|
|
291
|
+
|
|
292
|
+
def vcs_diff_raw(self, **kwargs) -> Any:
|
|
293
|
+
return self._request("GET", "/vcs/diff/raw", params=kwargs)
|
|
294
|
+
|
|
295
|
+
def vcs_apply(self, patch: str, **kwargs) -> Any:
|
|
296
|
+
return self._request("POST", "/vcs/apply", json_body={"patch": patch, **kwargs})
|
|
297
|
+
|
|
298
|
+
# ------------------------------------------------------------------
|
|
299
|
+
# LSP / Formatter
|
|
300
|
+
# ------------------------------------------------------------------
|
|
301
|
+
|
|
302
|
+
def lsp_status(self, **kwargs) -> Any:
|
|
303
|
+
return self._request("GET", "/lsp", params=kwargs)
|
|
304
|
+
|
|
305
|
+
def formatter_status(self, **kwargs) -> Any:
|
|
306
|
+
return self._request("GET", "/formatter", params=kwargs)
|
|
307
|
+
|
|
308
|
+
# ------------------------------------------------------------------
|
|
309
|
+
# Provider
|
|
310
|
+
# ------------------------------------------------------------------
|
|
311
|
+
|
|
312
|
+
def provider_list(self, **kwargs) -> Any:
|
|
313
|
+
return self._request("GET", "/provider", params=kwargs)
|
|
314
|
+
|
|
315
|
+
def provider_auth(self, provider_id: str, **kwargs) -> Any:
|
|
316
|
+
return self._request("GET", f"/provider/{provider_id}/auth", params=kwargs)
|
|
317
|
+
|
|
318
|
+
# ------------------------------------------------------------------
|
|
319
|
+
# MCP
|
|
320
|
+
# ------------------------------------------------------------------
|
|
321
|
+
|
|
322
|
+
def mcp_list(self, **kwargs) -> Any:
|
|
323
|
+
return self._request("GET", "/mcp", params=kwargs)
|
|
324
|
+
|
|
325
|
+
def mcp_status(self, **kwargs) -> Any:
|
|
326
|
+
return self._request("GET", "/mcp/status", params=kwargs)
|
|
327
|
+
|
|
328
|
+
def mcp_add(self, config: Any) -> Any:
|
|
329
|
+
return self._request("PUT", "/mcp", json_body={"config": config})
|
|
330
|
+
|
|
331
|
+
def mcp_connect(self, name: str, **kwargs) -> Any:
|
|
332
|
+
return self._request("POST", f"/mcp/{name}/connect", json_body=kwargs or None)
|
|
333
|
+
|
|
334
|
+
def mcp_disconnect(self, name: str) -> Any:
|
|
335
|
+
return self._request("DELETE", f"/mcp/{name}/connect")
|
|
336
|
+
|
|
337
|
+
# ------------------------------------------------------------------
|
|
338
|
+
# Tool
|
|
339
|
+
# ------------------------------------------------------------------
|
|
340
|
+
|
|
341
|
+
def tool_list(self, **kwargs) -> Any:
|
|
342
|
+
return self._request("GET", "/experimental/tool", params=kwargs)
|
|
343
|
+
|
|
344
|
+
def tool_ids(self, **kwargs) -> Any:
|
|
345
|
+
return self._request("GET", "/experimental/tool/ids", params=kwargs)
|
|
346
|
+
|
|
347
|
+
# ------------------------------------------------------------------
|
|
348
|
+
# Permission
|
|
349
|
+
# ------------------------------------------------------------------
|
|
350
|
+
|
|
351
|
+
def permission_list(self, **kwargs) -> Any:
|
|
352
|
+
return self._request("GET", "/permission", params=kwargs)
|
|
353
|
+
|
|
354
|
+
def permission_reply(self, permission_id: str, **kwargs) -> Any:
|
|
355
|
+
return self._request("POST", f"/permission/{permission_id}", json_body=kwargs or None)
|
|
356
|
+
|
|
357
|
+
# ------------------------------------------------------------------
|
|
358
|
+
# Question
|
|
359
|
+
# ------------------------------------------------------------------
|
|
360
|
+
|
|
361
|
+
def question_list(self, **kwargs) -> Any:
|
|
362
|
+
return self._request("GET", "/question", params=kwargs)
|
|
363
|
+
|
|
364
|
+
def question_reply(self, question_id: str, answer: Any) -> Any:
|
|
365
|
+
return self._request("POST", f"/question/{question_id}", json_body={"answer": answer})
|
|
366
|
+
|
|
367
|
+
def question_reject(self, question_id: str) -> Any:
|
|
368
|
+
return self._request("DELETE", f"/question/{question_id}")
|
|
369
|
+
|
|
370
|
+
# ------------------------------------------------------------------
|
|
371
|
+
# Event (SSE)
|
|
372
|
+
# ------------------------------------------------------------------
|
|
373
|
+
|
|
374
|
+
def event_subscribe(self, **kwargs) -> httpx.Response:
|
|
375
|
+
return self._request_stream("GET", "/event", params=kwargs)
|
|
376
|
+
|
|
377
|
+
# ------------------------------------------------------------------
|
|
378
|
+
# PTY
|
|
379
|
+
# ------------------------------------------------------------------
|
|
380
|
+
|
|
381
|
+
def pty_list(self, **kwargs) -> Any:
|
|
382
|
+
return self._request("GET", "/pty", params=kwargs)
|
|
383
|
+
|
|
384
|
+
def pty_create(self, **kwargs) -> Any:
|
|
385
|
+
return self._request("POST", "/pty", json_body=kwargs or None)
|
|
386
|
+
|
|
387
|
+
def pty_get(self, pty_id: str) -> Any:
|
|
388
|
+
return self._request("GET", f"/pty/{pty_id}")
|
|
389
|
+
|
|
390
|
+
def pty_remove(self, pty_id: str) -> Any:
|
|
391
|
+
return self._request("DELETE", f"/pty/{pty_id}")
|
|
392
|
+
|
|
393
|
+
def pty_update(self, pty_id: str, **kwargs) -> Any:
|
|
394
|
+
return self._request("PATCH", f"/pty/{pty_id}", json_body=kwargs or None)
|
|
395
|
+
|
|
396
|
+
def pty_shells(self, **kwargs) -> Any:
|
|
397
|
+
return self._request("GET", "/pty/shells", params=kwargs)
|
|
398
|
+
|
|
399
|
+
# ------------------------------------------------------------------
|
|
400
|
+
# Path
|
|
401
|
+
# ------------------------------------------------------------------
|
|
402
|
+
|
|
403
|
+
def path_get(self, **kwargs) -> Any:
|
|
404
|
+
return self._request("GET", "/path", params=kwargs)
|
|
405
|
+
|
|
406
|
+
# ------------------------------------------------------------------
|
|
407
|
+
# Instance
|
|
408
|
+
# ------------------------------------------------------------------
|
|
409
|
+
|
|
410
|
+
def instance_dispose(self, **kwargs) -> Any:
|
|
411
|
+
return self._request("POST", "/instance/dispose", params=kwargs)
|
|
412
|
+
|
|
413
|
+
# ------------------------------------------------------------------
|
|
414
|
+
# Command
|
|
415
|
+
# ------------------------------------------------------------------
|
|
416
|
+
|
|
417
|
+
def command_list(self, **kwargs) -> Any:
|
|
418
|
+
return self._request("GET", "/command", params=kwargs)
|
|
419
|
+
|
|
420
|
+
# ------------------------------------------------------------------
|
|
421
|
+
# Project
|
|
422
|
+
# ------------------------------------------------------------------
|
|
423
|
+
|
|
424
|
+
def project_current(self, **kwargs) -> Any:
|
|
425
|
+
return self._request("GET", "/project/current", params=kwargs)
|
|
426
|
+
|
|
427
|
+
def project_list(self, **kwargs) -> Any:
|
|
428
|
+
return self._request("GET", "/project", params=kwargs)
|
|
429
|
+
|
|
430
|
+
def project_update(self, **kwargs) -> Any:
|
|
431
|
+
return self._request("PATCH", "/project", json_body=kwargs or None)
|
|
432
|
+
|
|
433
|
+
def project_init_git(self, **kwargs) -> Any:
|
|
434
|
+
return self._request("POST", "/project/init-git", json_body=kwargs or None)
|
|
435
|
+
|
|
436
|
+
# ------------------------------------------------------------------
|
|
437
|
+
# Worktree (experimental)
|
|
438
|
+
# ------------------------------------------------------------------
|
|
439
|
+
|
|
440
|
+
def worktree_list(self, **kwargs) -> Any:
|
|
441
|
+
return self._request("GET", "/experimental/worktree", params=kwargs)
|
|
442
|
+
|
|
443
|
+
def worktree_create(self, **kwargs) -> Any:
|
|
444
|
+
return self._request("POST", "/experimental/worktree", json_body=kwargs or None)
|
|
445
|
+
|
|
446
|
+
def worktree_remove(self, **kwargs) -> Any:
|
|
447
|
+
return self._request("DELETE", "/experimental/worktree", params=kwargs)
|
|
448
|
+
|
|
449
|
+
def worktree_reset(self, **kwargs) -> Any:
|
|
450
|
+
return self._request("POST", "/experimental/worktree/reset", json_body=kwargs or None)
|
|
451
|
+
|
|
452
|
+
# ------------------------------------------------------------------
|
|
453
|
+
# Workspace (experimental)
|
|
454
|
+
# ------------------------------------------------------------------
|
|
455
|
+
|
|
456
|
+
def workspace_list(self, **kwargs) -> Any:
|
|
457
|
+
return self._request("GET", "/experimental/workspace", params=kwargs)
|
|
458
|
+
|
|
459
|
+
def workspace_create(self, **kwargs) -> Any:
|
|
460
|
+
return self._request("POST", "/experimental/workspace", json_body=kwargs or None)
|
|
461
|
+
|
|
462
|
+
def workspace_status(self, **kwargs) -> Any:
|
|
463
|
+
return self._request("GET", "/experimental/workspace/status", params=kwargs)
|
|
464
|
+
|
|
465
|
+
def workspace_remove(self, workspace_id: str) -> Any:
|
|
466
|
+
return self._request("DELETE", f"/experimental/workspace/{workspace_id}")
|
|
467
|
+
|
|
468
|
+
def workspace_warp(self, **kwargs) -> Any:
|
|
469
|
+
return self._request("POST", "/experimental/workspace/warp", json_body=kwargs or None)
|
|
470
|
+
|
|
471
|
+
# ------------------------------------------------------------------
|
|
472
|
+
# Sync (experimental)
|
|
473
|
+
# ------------------------------------------------------------------
|
|
474
|
+
|
|
475
|
+
def sync_start(self, **kwargs) -> Any:
|
|
476
|
+
return self._request("POST", "/experimental/sync/start", json_body=kwargs or None)
|
|
477
|
+
|
|
478
|
+
def sync_steal(self, **kwargs) -> Any:
|
|
479
|
+
return self._request("POST", "/experimental/sync/steal", json_body=kwargs or None)
|
|
480
|
+
|
|
481
|
+
def sync_replay(self, session_id: str) -> Any:
|
|
482
|
+
return self._request("POST", f"/experimental/sync/replay/{session_id}")
|
|
483
|
+
|
|
484
|
+
def sync_history(self, session_id: str) -> Any:
|
|
485
|
+
return self._request("GET", f"/experimental/sync/history/{session_id}")
|
|
486
|
+
|
|
487
|
+
# ------------------------------------------------------------------
|
|
488
|
+
# TUI
|
|
489
|
+
# ------------------------------------------------------------------
|
|
490
|
+
|
|
491
|
+
def tui_submit_prompt(self, **kwargs) -> Any:
|
|
492
|
+
return self._request("POST", "/tui/submit", json_body=kwargs or None)
|
|
493
|
+
|
|
494
|
+
def tui_append_prompt(self, **kwargs) -> Any:
|
|
495
|
+
return self._request("POST", "/tui/append", json_body=kwargs or None)
|
|
496
|
+
|
|
497
|
+
def tui_clear_prompt(self) -> Any:
|
|
498
|
+
return self._request("POST", "/tui/clear")
|
|
499
|
+
|
|
500
|
+
def tui_execute_command(self, **kwargs) -> Any:
|
|
501
|
+
return self._request("POST", "/tui/command", json_body=kwargs or None)
|
|
502
|
+
|
|
503
|
+
def tui_show_toast(self, **kwargs) -> Any:
|
|
504
|
+
return self._request("POST", "/tui/toast", json_body=kwargs or None)
|
|
505
|
+
|
|
506
|
+
def tui_open_sessions(self) -> Any:
|
|
507
|
+
return self._request("POST", "/tui/sessions")
|
|
508
|
+
|
|
509
|
+
def tui_open_models(self) -> Any:
|
|
510
|
+
return self._request("POST", "/tui/models")
|
|
511
|
+
|
|
512
|
+
def tui_open_themes(self) -> Any:
|
|
513
|
+
return self._request("POST", "/tui/themes")
|
|
514
|
+
|
|
515
|
+
def tui_open_help(self) -> Any:
|
|
516
|
+
return self._request("POST", "/tui/help")
|
|
517
|
+
|
|
518
|
+
def tui_publish(self, **kwargs) -> Any:
|
|
519
|
+
return self._request("POST", "/tui/publish", json_body=kwargs or None)
|
|
520
|
+
|
|
521
|
+
def tui_control_response(self, **kwargs) -> Any:
|
|
522
|
+
return self._request("POST", "/tui/control/response", json_body=kwargs or None)
|
|
523
|
+
|
|
524
|
+
def tui_control_next(self, session_id: str) -> Any:
|
|
525
|
+
return self._request("POST", f"/tui/control/next/{session_id}")
|
|
526
|
+
|
|
527
|
+
# ------------------------------------------------------------------
|
|
528
|
+
# Close
|
|
529
|
+
# ------------------------------------------------------------------
|
|
530
|
+
|
|
531
|
+
def close(self) -> None:
|
|
532
|
+
self._client.close()
|
opencode/_errors.py
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class OpencodeError(Exception):
|
|
5
|
+
def __init__(self, message: str, *, status: int | None = None, body: object = None):
|
|
6
|
+
self.status = status
|
|
7
|
+
self.body = body
|
|
8
|
+
super().__init__(message)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class ApiError(OpencodeError):
|
|
12
|
+
...
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class BinaryNotFound(OpencodeError):
|
|
16
|
+
...
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class ServerStartupTimeout(OpencodeError):
|
|
20
|
+
...
|
opencode/_models.py
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
try:
|
|
4
|
+
from typing import NotRequired
|
|
5
|
+
except ImportError:
|
|
6
|
+
from typing_extensions import NotRequired # Python <3.11
|
|
7
|
+
|
|
8
|
+
from typing import Any, Dict, List, Literal, TypedDict
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class SessionInfo(TypedDict):
|
|
12
|
+
id: str
|
|
13
|
+
agent: NotRequired[str | None]
|
|
14
|
+
model: NotRequired[str | None]
|
|
15
|
+
title: NotRequired[str | None]
|
|
16
|
+
created: NotRequired[float]
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class AssistantMessageText(TypedDict):
|
|
20
|
+
type: Literal["text"]
|
|
21
|
+
text: str
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class AssistantMessageReasoning(TypedDict):
|
|
25
|
+
type: Literal["reasoning"]
|
|
26
|
+
text: str
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class AssistantMessageTool(TypedDict):
|
|
30
|
+
type: Literal["tool"]
|
|
31
|
+
tool: str
|
|
32
|
+
input: Any
|
|
33
|
+
output: NotRequired[str | None]
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class ToolCall(TypedDict):
|
|
37
|
+
name: str
|
|
38
|
+
input: Dict[str, Any]
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class ToolUse(TypedDict):
|
|
42
|
+
type: Literal["tool-use"]
|
|
43
|
+
toolUseID: str
|
|
44
|
+
tool: ToolCall
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class ToolResult(TypedDict):
|
|
48
|
+
type: Literal["tool-result"]
|
|
49
|
+
toolUseID: str
|
|
50
|
+
tool: ToolCall
|
|
51
|
+
output: Dict[str, Any]
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
AssistantContent = AssistantMessageText | AssistantMessageReasoning | AssistantMessageTool | ToolUse
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class AssistantMessage(TypedDict):
|
|
58
|
+
id: str
|
|
59
|
+
type: Literal["assistant"]
|
|
60
|
+
agent: NotRequired[str | None]
|
|
61
|
+
model: NotRequired[Dict[str, str] | None]
|
|
62
|
+
content: List[AssistantContent]
|
|
63
|
+
structured: NotRequired[Any]
|
|
64
|
+
finish: NotRequired[str | None]
|
|
65
|
+
cost: NotRequired[float | None]
|
|
66
|
+
tokens: NotRequired[Dict[str, int] | None]
|
|
67
|
+
time: Dict[str, float]
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class UserMessage(TypedDict):
|
|
71
|
+
id: str
|
|
72
|
+
type: Literal["user"]
|
|
73
|
+
text: str
|
|
74
|
+
files: NotRequired[List[Any] | None]
|
|
75
|
+
agents: NotRequired[List[Any] | None]
|
|
76
|
+
references: NotRequired[List[Any] | None]
|
|
77
|
+
time: Dict[str, float]
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
SessionMessage = AssistantMessage | UserMessage
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
class PromptFileAttachment(TypedDict):
|
|
84
|
+
uri: str
|
|
85
|
+
mime: NotRequired[str | None]
|
|
86
|
+
name: NotRequired[str | None]
|
|
87
|
+
description: NotRequired[str | None]
|
|
88
|
+
source: NotRequired[Dict[str, Any] | None]
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
class PromptAgentAttachment(TypedDict):
|
|
92
|
+
name: str
|
|
93
|
+
source: NotRequired[Dict[str, Any] | None]
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
class PromptReferenceAttachment(TypedDict):
|
|
97
|
+
name: str
|
|
98
|
+
kind: NotRequired[str | None]
|
|
99
|
+
uri: NotRequired[str | None]
|
|
100
|
+
repository: NotRequired[str | None]
|
|
101
|
+
branch: NotRequired[str | None]
|
|
102
|
+
target: NotRequired[str | None]
|
|
103
|
+
targetUri: NotRequired[str | None]
|
|
104
|
+
source: NotRequired[Dict[str, Any] | None]
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class OutputFormatJsonSchema(TypedDict):
|
|
108
|
+
type: Literal["json_schema"]
|
|
109
|
+
schema: Dict[str, Any]
|
|
110
|
+
retryCount: NotRequired[int | None]
|