opencode-python-sdk 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.
Files changed (55) hide show
  1. opencode/.generated.json +39 -0
  2. opencode/__init__.py +156 -0
  3. opencode/_base_client.py +518 -0
  4. opencode/_client.py +167 -0
  5. opencode/_constants.py +27 -0
  6. opencode/_errors.py +547 -0
  7. opencode/_exceptions.py +249 -0
  8. opencode/_models.py +54 -0
  9. opencode/_pagination.py +192 -0
  10. opencode/_qs.py +95 -0
  11. opencode/_resource.py +42 -0
  12. opencode/_server.py +327 -0
  13. opencode/_streaming.py +227 -0
  14. opencode/_types.py +77 -0
  15. opencode/_unions.py +46 -0
  16. opencode/_version.py +8 -0
  17. opencode/py.typed +0 -0
  18. opencode/resources/__init__.py +364 -0
  19. opencode/resources/agent.py +177 -0
  20. opencode/resources/command.py +98 -0
  21. opencode/resources/config.py +238 -0
  22. opencode/resources/credential.py +382 -0
  23. opencode/resources/debug.py +174 -0
  24. opencode/resources/event.py +84 -0
  25. opencode/resources/experimental.py +760 -0
  26. opencode/resources/file.py +353 -0
  27. opencode/resources/form.py +98 -0
  28. opencode/resources/generate.py +108 -0
  29. opencode/resources/integration.py +1023 -0
  30. opencode/resources/location.py +160 -0
  31. opencode/resources/mcp.py +488 -0
  32. opencode/resources/message.py +151 -0
  33. opencode/resources/migration.py +118 -0
  34. opencode/resources/model.py +175 -0
  35. opencode/resources/permission.py +698 -0
  36. opencode/resources/plugin.py +248 -0
  37. opencode/resources/project.py +185 -0
  38. opencode/resources/provider.py +181 -0
  39. opencode/resources/pty.py +517 -0
  40. opencode/resources/reference.py +98 -0
  41. opencode/resources/rpc.py +111 -0
  42. opencode/resources/server.py +228 -0
  43. opencode/resources/session.py +3553 -0
  44. opencode/resources/shell.py +410 -0
  45. opencode/resources/skill.py +98 -0
  46. opencode/resources/vcs.py +496 -0
  47. opencode/resources/voice.py +111 -0
  48. opencode/resources/websearch.py +182 -0
  49. opencode/resources/worktree.py +334 -0
  50. opencode/types/__init__.py +1462 -0
  51. opencode/types/_generated.py +8540 -0
  52. opencode_python_sdk-0.1.0.dist-info/METADATA +317 -0
  53. opencode_python_sdk-0.1.0.dist-info/RECORD +55 -0
  54. opencode_python_sdk-0.1.0.dist-info/WHEEL +4 -0
  55. opencode_python_sdk-0.1.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,3553 @@
1
+ # This file is generated by `python -m codegen` from spec/contract.json. Do not edit it by hand.
2
+ # OpenCode 2.1.2
3
+
4
+ """The ``session`` resource."""
5
+
6
+ from __future__ import annotations
7
+
8
+ import builtins
9
+ from collections.abc import Mapping, Sequence
10
+ from functools import cached_property
11
+ from typing import Any, Literal, cast
12
+
13
+ from .._base_client import RequestOptions
14
+ from .._pagination import AsyncPaginator, SyncCursorPage
15
+ from .._qs import encode_path_segment
16
+ from .._resource import AsyncAPIResource, SyncAPIResource
17
+ from .._streaming import AsyncStream, Stream
18
+ from .._types import NOT_GIVEN, Body, Headers, NotGiven, OpenEnum, Query, Timeout
19
+ from ..types import (
20
+ AbsolutePath,
21
+ AgentID,
22
+ EventSeq,
23
+ FileDiffInfo,
24
+ FormAnswer,
25
+ FormDetail,
26
+ FormFields,
27
+ FormID,
28
+ FormInfo,
29
+ FormMetadata,
30
+ InstructionEntryInfo,
31
+ InstructionEntryKey,
32
+ LocationPublicRef,
33
+ ModelRef,
34
+ PermissionRuleset,
35
+ ProjectID,
36
+ PromptAgentAttachment,
37
+ PromptInputFileAttachment,
38
+ PromptInputSkillAttachment,
39
+ RelativePath,
40
+ SessionGenerateResponseData,
41
+ SessionID,
42
+ SessionInboxCompaction,
43
+ SessionInboxDelivery,
44
+ SessionInboxInfo,
45
+ SessionInboxSynthetic,
46
+ SessionInboxUser,
47
+ SessionInfo,
48
+ SessionInterruptResponse,
49
+ SessionLogItem,
50
+ SessionMessageID,
51
+ SessionMessageInfo,
52
+ SessionMetadata,
53
+ SessionRevert,
54
+ SessionsCursor,
55
+ SessionsResponse,
56
+ SessionStatsInfo,
57
+ SessionTransferData,
58
+ SkillID,
59
+ )
60
+
61
+ __all__ = ["SessionResource", "AsyncSessionResource"]
62
+
63
+
64
+ class SessionRevertResource(SyncAPIResource):
65
+ """Operations under ``client.session.revert`` (OpenCode ``session.revert``)."""
66
+
67
+ def stage(
68
+ self,
69
+ session_id: SessionID,
70
+ *,
71
+ message_id: SessionMessageID,
72
+ files: bool | NotGiven | None = NOT_GIVEN,
73
+ extra_headers: Headers | None = None,
74
+ extra_query: Query | None = None,
75
+ extra_body: Body | None = None,
76
+ timeout: Timeout | NotGiven = NOT_GIVEN,
77
+ ) -> SessionRevert:
78
+ """Stage session revert.
79
+
80
+ Stage or move a reversible session boundary and optionally apply its file changes.
81
+
82
+ Raises:
83
+ InvalidRequestError
84
+ UnauthorizedError
85
+ MessageNotFoundError
86
+ SessionNotFoundError
87
+ LocationNotFoundError
88
+ SessionBusyError
89
+ UnknownError
90
+
91
+ ``POST /api/session/:sessionID/revert/stage``
92
+ """
93
+ return cast(
94
+ "SessionRevert",
95
+ self._client.request(
96
+ RequestOptions(
97
+ method="POST",
98
+ path=f"/api/session/{encode_path_segment(session_id)}/revert/stage",
99
+ body={"messageID": message_id, "files": files},
100
+ extra_headers=extra_headers,
101
+ extra_query=extra_query,
102
+ extra_body=extra_body,
103
+ timeout=timeout,
104
+ ),
105
+ response_type=SessionRevert,
106
+ unwrap=True,
107
+ ),
108
+ )
109
+
110
+ def clear(
111
+ self,
112
+ session_id: SessionID,
113
+ *,
114
+ extra_headers: Headers | None = None,
115
+ extra_query: Query | None = None,
116
+ extra_body: Body | None = None,
117
+ timeout: Timeout | NotGiven = NOT_GIVEN,
118
+ ) -> None:
119
+ """Clear staged revert.
120
+
121
+ Raises:
122
+ InvalidRequestError
123
+ UnauthorizedError
124
+ SessionNotFoundError
125
+ LocationNotFoundError
126
+ SessionBusyError
127
+ UnknownError
128
+
129
+ ``DELETE /api/session/:sessionID/revert``
130
+ """
131
+ self._client.request(
132
+ RequestOptions(
133
+ method="DELETE",
134
+ path=f"/api/session/{encode_path_segment(session_id)}/revert",
135
+ extra_headers=extra_headers,
136
+ extra_query=extra_query,
137
+ extra_body=extra_body,
138
+ timeout=timeout,
139
+ ),
140
+ kind="void",
141
+ )
142
+
143
+ def commit(
144
+ self,
145
+ session_id: SessionID,
146
+ *,
147
+ extra_headers: Headers | None = None,
148
+ extra_query: Query | None = None,
149
+ extra_body: Body | None = None,
150
+ timeout: Timeout | NotGiven = NOT_GIVEN,
151
+ ) -> None:
152
+ """Commit staged revert.
153
+
154
+ Raises:
155
+ InvalidRequestError
156
+ UnauthorizedError
157
+ SessionNotFoundError
158
+ LocationNotFoundError
159
+ SessionBusyError
160
+
161
+ ``POST /api/session/:sessionID/revert/commit``
162
+ """
163
+ self._client.request(
164
+ RequestOptions(
165
+ method="POST",
166
+ path=f"/api/session/{encode_path_segment(session_id)}/revert/commit",
167
+ extra_headers=extra_headers,
168
+ extra_query=extra_query,
169
+ extra_body=extra_body,
170
+ timeout=timeout,
171
+ ),
172
+ kind="void",
173
+ )
174
+
175
+
176
+ class SessionInboxResource(SyncAPIResource):
177
+ """Operations under ``client.session.inbox`` (OpenCode ``session.inbox``)."""
178
+
179
+ def list(
180
+ self,
181
+ session_id: SessionID,
182
+ *,
183
+ extra_headers: Headers | None = None,
184
+ extra_query: Query | None = None,
185
+ extra_body: Body | None = None,
186
+ timeout: Timeout | NotGiven = NOT_GIVEN,
187
+ ) -> builtins.list[SessionInboxInfo]:
188
+ """List session inbox.
189
+
190
+ List durable enqueued session work not yet delivered, ordered by enqueue sequence. Includes user, synthetic, compaction, and move items.
191
+
192
+ Raises:
193
+ InvalidRequestError
194
+ UnauthorizedError
195
+ SessionNotFoundError
196
+
197
+ ``GET /api/session/:sessionID/inbox``
198
+ """
199
+ return cast(
200
+ "builtins.list[SessionInboxInfo]",
201
+ self._client.request(
202
+ RequestOptions(
203
+ method="GET",
204
+ path=f"/api/session/{encode_path_segment(session_id)}/inbox",
205
+ extra_headers=extra_headers,
206
+ extra_query=extra_query,
207
+ extra_body=extra_body,
208
+ timeout=timeout,
209
+ ),
210
+ response_type=builtins.list[SessionInboxInfo],
211
+ unwrap=True,
212
+ ),
213
+ )
214
+
215
+ def cancel(
216
+ self,
217
+ session_id: SessionID,
218
+ inbox_id: SessionMessageID,
219
+ *,
220
+ extra_headers: Headers | None = None,
221
+ extra_query: Query | None = None,
222
+ extra_body: Body | None = None,
223
+ timeout: Timeout | NotGiven = NOT_GIVEN,
224
+ ) -> None:
225
+ """Cancel inbox input.
226
+
227
+ Cancel an inbox item that has not yet been delivered. Unavailable items are a no-op.
228
+
229
+ Raises:
230
+ InvalidRequestError
231
+ UnauthorizedError
232
+ SessionNotFoundError
233
+
234
+ ``DELETE /api/session/:sessionID/inbox/:inboxID``
235
+ """
236
+ self._client.request(
237
+ RequestOptions(
238
+ method="DELETE",
239
+ path=f"/api/session/{encode_path_segment(session_id)}/inbox/{encode_path_segment(inbox_id)}",
240
+ extra_headers=extra_headers,
241
+ extra_query=extra_query,
242
+ extra_body=extra_body,
243
+ timeout=timeout,
244
+ ),
245
+ kind="void",
246
+ )
247
+
248
+ def update(
249
+ self,
250
+ session_id: SessionID,
251
+ inbox_id: SessionMessageID,
252
+ *,
253
+ delivery: SessionInboxDelivery,
254
+ extra_headers: Headers | None = None,
255
+ extra_query: Query | None = None,
256
+ extra_body: Body | None = None,
257
+ timeout: Timeout | NotGiven = NOT_GIVEN,
258
+ ) -> None:
259
+ """Update inbox item.
260
+
261
+ Change a pending inbox item's delivery mode. Steering wakes session execution.
262
+
263
+ Raises:
264
+ InvalidRequestError
265
+ UnauthorizedError
266
+ SessionNotFoundError
267
+ ConflictError
268
+
269
+ ``PATCH /api/session/:sessionID/inbox/:inboxID``
270
+ """
271
+ self._client.request(
272
+ RequestOptions(
273
+ method="PATCH",
274
+ path=f"/api/session/{encode_path_segment(session_id)}/inbox/{encode_path_segment(inbox_id)}",
275
+ body={"delivery": delivery},
276
+ extra_headers=extra_headers,
277
+ extra_query=extra_query,
278
+ extra_body=extra_body,
279
+ timeout=timeout,
280
+ ),
281
+ kind="void",
282
+ )
283
+
284
+
285
+ class SessionInstructionsEntryResource(SyncAPIResource):
286
+ """Operations under ``client.session.instructions.entry`` (OpenCode ``session.instructions.entry``)."""
287
+
288
+ def list(
289
+ self,
290
+ session_id: SessionID,
291
+ *,
292
+ extra_headers: Headers | None = None,
293
+ extra_query: Query | None = None,
294
+ extra_body: Body | None = None,
295
+ timeout: Timeout | NotGiven = NOT_GIVEN,
296
+ ) -> builtins.list[InstructionEntryInfo]:
297
+ """List instruction entries.
298
+
299
+ List API-managed instruction entries attached to the session.
300
+
301
+ This endpoint is experimental in OpenCode and may change without notice.
302
+
303
+ Raises:
304
+ InvalidRequestError
305
+ UnauthorizedError
306
+ SessionNotFoundError
307
+ LocationNotFoundError
308
+
309
+ ``GET /api/experimental/session/:sessionID/instructions/entries``
310
+ """
311
+ return cast(
312
+ "builtins.list[InstructionEntryInfo]",
313
+ self._client.request(
314
+ RequestOptions(
315
+ method="GET",
316
+ path=f"/api/experimental/session/{encode_path_segment(session_id)}/instructions/entries",
317
+ extra_headers=extra_headers,
318
+ extra_query=extra_query,
319
+ extra_body=extra_body,
320
+ timeout=timeout,
321
+ ),
322
+ response_type=builtins.list[InstructionEntryInfo],
323
+ unwrap=True,
324
+ ),
325
+ )
326
+
327
+ def put(
328
+ self,
329
+ session_id: SessionID,
330
+ key: InstructionEntryKey,
331
+ *,
332
+ value: Any,
333
+ extra_headers: Headers | None = None,
334
+ extra_query: Query | None = None,
335
+ extra_body: Body | None = None,
336
+ timeout: Timeout | NotGiven = NOT_GIVEN,
337
+ ) -> None:
338
+ """Put instruction entry.
339
+
340
+ Attach or replace one durable instruction entry. Changes announce as updates at the next step boundary.
341
+
342
+ This endpoint is experimental in OpenCode and may change without notice.
343
+
344
+ Raises:
345
+ InvalidRequestError
346
+ UnauthorizedError
347
+ SessionNotFoundError
348
+ LocationNotFoundError
349
+ InstructionEntryValueTooLargeError
350
+
351
+ ``PUT /api/experimental/session/:sessionID/instructions/entries/:key``
352
+ """
353
+ self._client.request(
354
+ RequestOptions(
355
+ method="PUT",
356
+ path=f"/api/experimental/session/{encode_path_segment(session_id)}/instructions/entries/{encode_path_segment(key)}",
357
+ body={"value": value},
358
+ extra_headers=extra_headers,
359
+ extra_query=extra_query,
360
+ extra_body=extra_body,
361
+ timeout=timeout,
362
+ ),
363
+ kind="void",
364
+ )
365
+
366
+ def remove(
367
+ self,
368
+ session_id: SessionID,
369
+ key: InstructionEntryKey,
370
+ *,
371
+ extra_headers: Headers | None = None,
372
+ extra_query: Query | None = None,
373
+ extra_body: Body | None = None,
374
+ timeout: Timeout | NotGiven = NOT_GIVEN,
375
+ ) -> None:
376
+ """Remove instruction entry.
377
+
378
+ Remove one instruction entry; the removal is announced to the model at the next step boundary.
379
+
380
+ This endpoint is experimental in OpenCode and may change without notice.
381
+
382
+ Raises:
383
+ InvalidRequestError
384
+ UnauthorizedError
385
+ SessionNotFoundError
386
+ LocationNotFoundError
387
+
388
+ ``DELETE /api/experimental/session/:sessionID/instructions/entries/:key``
389
+ """
390
+ self._client.request(
391
+ RequestOptions(
392
+ method="DELETE",
393
+ path=f"/api/experimental/session/{encode_path_segment(session_id)}/instructions/entries/{encode_path_segment(key)}",
394
+ extra_headers=extra_headers,
395
+ extra_query=extra_query,
396
+ extra_body=extra_body,
397
+ timeout=timeout,
398
+ ),
399
+ kind="void",
400
+ )
401
+
402
+
403
+ class SessionInstructionsResource(SyncAPIResource):
404
+ """Operations under ``client.session.instructions`` (OpenCode ``session.instructions``)."""
405
+
406
+ @cached_property
407
+ def entry(self) -> SessionInstructionsEntryResource:
408
+ return SessionInstructionsEntryResource(self._client)
409
+
410
+
411
+ class SessionMessageResource(SyncAPIResource):
412
+ """Operations under ``client.session.message`` (OpenCode ``session.message``)."""
413
+
414
+ def get(
415
+ self,
416
+ session_id: SessionID,
417
+ message_id: SessionMessageID,
418
+ *,
419
+ extra_headers: Headers | None = None,
420
+ extra_query: Query | None = None,
421
+ extra_body: Body | None = None,
422
+ timeout: Timeout | NotGiven = NOT_GIVEN,
423
+ ) -> SessionMessageInfo:
424
+ """Get session message.
425
+
426
+ Retrieve one projected message owned by the Session.
427
+
428
+ Raises:
429
+ InvalidRequestError
430
+ UnauthorizedError
431
+ SessionNotFoundError
432
+ MessageNotFoundError
433
+
434
+ ``GET /api/session/:sessionID/message/:messageID``
435
+ """
436
+ return cast(
437
+ "SessionMessageInfo",
438
+ self._client.request(
439
+ RequestOptions(
440
+ method="GET",
441
+ path=f"/api/session/{encode_path_segment(session_id)}/message/{encode_path_segment(message_id)}",
442
+ extra_headers=extra_headers,
443
+ extra_query=extra_query,
444
+ extra_body=extra_body,
445
+ timeout=timeout,
446
+ ),
447
+ response_type=SessionMessageInfo,
448
+ unwrap=True,
449
+ ),
450
+ )
451
+
452
+
453
+ class SessionFormResource(SyncAPIResource):
454
+ """Operations under ``client.session.form`` (OpenCode ``session.form``)."""
455
+
456
+ def list(
457
+ self,
458
+ session_id: str,
459
+ *,
460
+ extra_headers: Headers | None = None,
461
+ extra_query: Query | None = None,
462
+ extra_body: Body | None = None,
463
+ timeout: Timeout | NotGiven = NOT_GIVEN,
464
+ ) -> builtins.list[FormInfo]:
465
+ """List session forms.
466
+
467
+ Retrieve pending forms for a session.
468
+
469
+ Raises:
470
+ InvalidRequestError
471
+ UnauthorizedError
472
+ SessionNotFoundError
473
+ LocationNotFoundError
474
+
475
+ ``GET /api/session/:sessionID/form``
476
+ """
477
+ return cast(
478
+ "builtins.list[FormInfo]",
479
+ self._client.request(
480
+ RequestOptions(
481
+ method="GET",
482
+ path=f"/api/session/{encode_path_segment(session_id)}/form",
483
+ extra_headers=extra_headers,
484
+ extra_query=extra_query,
485
+ extra_body=extra_body,
486
+ timeout=timeout,
487
+ ),
488
+ response_type=builtins.list[FormInfo],
489
+ unwrap=True,
490
+ ),
491
+ )
492
+
493
+ def create(
494
+ self,
495
+ session_id: str,
496
+ *,
497
+ title: str,
498
+ fields: FormFields,
499
+ id: FormID | NotGiven | None = NOT_GIVEN,
500
+ metadata: FormMetadata | NotGiven = NOT_GIVEN,
501
+ extra_headers: Headers | None = None,
502
+ extra_query: Query | None = None,
503
+ extra_body: Body | None = None,
504
+ timeout: Timeout | NotGiven = NOT_GIVEN,
505
+ ) -> FormInfo:
506
+ """Create session form.
507
+
508
+ Create a form for a session.
509
+
510
+ Raises:
511
+ InvalidRequestError
512
+ UnauthorizedError
513
+ SessionNotFoundError
514
+ LocationNotFoundError
515
+ ConflictError
516
+
517
+ ``POST /api/session/:sessionID/form``
518
+ """
519
+ return cast(
520
+ "FormInfo",
521
+ self._client.request(
522
+ RequestOptions(
523
+ method="POST",
524
+ path=f"/api/session/{encode_path_segment(session_id)}/form",
525
+ body={"id": id, "title": title, "metadata": metadata, "fields": fields},
526
+ extra_headers=extra_headers,
527
+ extra_query=extra_query,
528
+ extra_body=extra_body,
529
+ timeout=timeout,
530
+ ),
531
+ response_type=FormInfo,
532
+ unwrap=True,
533
+ ),
534
+ )
535
+
536
+ def get(
537
+ self,
538
+ session_id: str,
539
+ form_id: FormID,
540
+ *,
541
+ extra_headers: Headers | None = None,
542
+ extra_query: Query | None = None,
543
+ extra_body: Body | None = None,
544
+ timeout: Timeout | NotGiven = NOT_GIVEN,
545
+ ) -> FormDetail:
546
+ """Get session form.
547
+
548
+ Retrieve a form and its current state for a session.
549
+
550
+ Raises:
551
+ InvalidRequestError
552
+ UnauthorizedError
553
+ SessionNotFoundError
554
+ FormNotFoundError
555
+ LocationNotFoundError
556
+
557
+ ``GET /api/session/:sessionID/form/:formID``
558
+ """
559
+ return cast(
560
+ "FormDetail",
561
+ self._client.request(
562
+ RequestOptions(
563
+ method="GET",
564
+ path=f"/api/session/{encode_path_segment(session_id)}/form/{encode_path_segment(form_id)}",
565
+ extra_headers=extra_headers,
566
+ extra_query=extra_query,
567
+ extra_body=extra_body,
568
+ timeout=timeout,
569
+ ),
570
+ response_type=FormDetail,
571
+ unwrap=True,
572
+ ),
573
+ )
574
+
575
+ def reply(
576
+ self,
577
+ session_id: str,
578
+ form_id: FormID,
579
+ *,
580
+ answer: FormAnswer,
581
+ extra_headers: Headers | None = None,
582
+ extra_query: Query | None = None,
583
+ extra_body: Body | None = None,
584
+ timeout: Timeout | NotGiven = NOT_GIVEN,
585
+ ) -> None:
586
+ """Reply to form.
587
+
588
+ Submit an answer to a pending form.
589
+
590
+ Raises:
591
+ FormInvalidAnswerError
592
+ InvalidRequestError
593
+ UnauthorizedError
594
+ SessionNotFoundError
595
+ FormNotFoundError
596
+ LocationNotFoundError
597
+ FormAlreadySettledError
598
+
599
+ ``POST /api/session/:sessionID/form/:formID/reply``
600
+ """
601
+ self._client.request(
602
+ RequestOptions(
603
+ method="POST",
604
+ path=f"/api/session/{encode_path_segment(session_id)}/form/{encode_path_segment(form_id)}/reply",
605
+ body={"answer": answer},
606
+ extra_headers=extra_headers,
607
+ extra_query=extra_query,
608
+ extra_body=extra_body,
609
+ timeout=timeout,
610
+ ),
611
+ kind="void",
612
+ )
613
+
614
+ def cancel(
615
+ self,
616
+ session_id: str,
617
+ form_id: FormID,
618
+ *,
619
+ message: str | NotGiven | None = NOT_GIVEN,
620
+ extra_headers: Headers | None = None,
621
+ extra_query: Query | None = None,
622
+ extra_body: Body | None = None,
623
+ timeout: Timeout | NotGiven = NOT_GIVEN,
624
+ ) -> None:
625
+ """Cancel form.
626
+
627
+ Cancel a pending form, optionally telling the asker why it was not answered.
628
+
629
+ Raises:
630
+ InvalidRequestError
631
+ UnauthorizedError
632
+ SessionNotFoundError
633
+ FormNotFoundError
634
+ LocationNotFoundError
635
+ FormAlreadySettledError
636
+
637
+ ``DELETE /api/session/:sessionID/form/:formID``
638
+ """
639
+ self._client.request(
640
+ RequestOptions(
641
+ method="DELETE",
642
+ path=f"/api/session/{encode_path_segment(session_id)}/form/{encode_path_segment(form_id)}",
643
+ query={"message": message},
644
+ extra_headers=extra_headers,
645
+ extra_query=extra_query,
646
+ extra_body=extra_body,
647
+ timeout=timeout,
648
+ ),
649
+ kind="void",
650
+ )
651
+
652
+
653
+ class SessionResource(SyncAPIResource):
654
+ """Operations under ``client.session`` (OpenCode ``session``)."""
655
+
656
+ @cached_property
657
+ def revert(self) -> SessionRevertResource:
658
+ return SessionRevertResource(self._client)
659
+
660
+ @cached_property
661
+ def inbox(self) -> SessionInboxResource:
662
+ return SessionInboxResource(self._client)
663
+
664
+ @cached_property
665
+ def instructions(self) -> SessionInstructionsResource:
666
+ return SessionInstructionsResource(self._client)
667
+
668
+ @cached_property
669
+ def message(self) -> SessionMessageResource:
670
+ return SessionMessageResource(self._client)
671
+
672
+ @cached_property
673
+ def form(self) -> SessionFormResource:
674
+ return SessionFormResource(self._client)
675
+
676
+ def list(
677
+ self,
678
+ *,
679
+ limit: int | NotGiven | None = NOT_GIVEN,
680
+ order: OpenEnum[Literal["asc", "desc"]] | NotGiven | None = NOT_GIVEN,
681
+ search: str | NotGiven | None = NOT_GIVEN,
682
+ parent_id: SessionID | NotGiven | None = NOT_GIVEN,
683
+ archived: bool | NotGiven | None = NOT_GIVEN,
684
+ directory: AbsolutePath | NotGiven | None = NOT_GIVEN,
685
+ project: ProjectID | NotGiven | None = NOT_GIVEN,
686
+ subpath: RelativePath | NotGiven | None = NOT_GIVEN,
687
+ cursor: SessionsCursor | NotGiven | None = NOT_GIVEN,
688
+ extra_headers: Headers | None = None,
689
+ extra_query: Query | None = None,
690
+ extra_body: Body | None = None,
691
+ timeout: Timeout | NotGiven = NOT_GIVEN,
692
+ ) -> SyncCursorPage[SessionInfo]:
693
+ """List sessions.
694
+
695
+ Retrieve sessions in the requested order. Items keep that order across pages; use cursor.next or cursor.previous to move through the ordered list.
696
+
697
+ Args:
698
+ limit: Maximum number of sessions to return. Defaults to the newest 50 sessions.
699
+ order: Session order for the first page. Use desc for newest first or asc for oldest first.
700
+ parent_id: Filter by parent session. Use null to return only root sessions.
701
+ archived: Filter by archive state. Use true to return only archived sessions or false to exclude them. Omit to include both.
702
+
703
+ Raises:
704
+ InvalidCursorError
705
+ InvalidRequestError
706
+ UnauthorizedError
707
+
708
+ ``GET /api/session``
709
+ """
710
+ return self._client.page(
711
+ RequestOptions(
712
+ method="GET",
713
+ path="/api/session",
714
+ query={
715
+ "limit": limit,
716
+ "order": order,
717
+ "search": search,
718
+ "parentID": parent_id,
719
+ "archived": archived,
720
+ "directory": directory,
721
+ "project": project,
722
+ "subpath": subpath,
723
+ "cursor": cursor,
724
+ },
725
+ extra_headers=extra_headers,
726
+ extra_query=extra_query,
727
+ extra_body=extra_body,
728
+ timeout=timeout,
729
+ ),
730
+ response_type=SessionsResponse,
731
+ )
732
+
733
+ def stats(
734
+ self,
735
+ *,
736
+ from_: float | OpenEnum[Literal["Infinity", "-Infinity", "NaN"]] | NotGiven | None = NOT_GIVEN,
737
+ to: float | OpenEnum[Literal["Infinity", "-Infinity", "NaN"]] | NotGiven | None = NOT_GIVEN,
738
+ project: ProjectID | NotGiven | None = NOT_GIVEN,
739
+ timezone: str | NotGiven | None = NOT_GIVEN,
740
+ tools: OpenEnum[Literal["none", "summary", "detail"]] | NotGiven | None = NOT_GIVEN,
741
+ extra_headers: Headers | None = None,
742
+ extra_query: Query | None = None,
743
+ extra_body: Body | None = None,
744
+ timeout: Timeout | NotGiven = NOT_GIVEN,
745
+ ) -> SessionStatsInfo:
746
+ """Get session statistics.
747
+
748
+ Aggregate local session activity, usage, and tool reliability for a time range.
749
+
750
+ This endpoint is experimental in OpenCode and may change without notice.
751
+
752
+ Raises:
753
+ InvalidRequestError
754
+ UnauthorizedError
755
+
756
+ ``GET /api/experimental/session/stats``
757
+ """
758
+ return cast(
759
+ "SessionStatsInfo",
760
+ self._client.request(
761
+ RequestOptions(
762
+ method="GET",
763
+ path="/api/experimental/session/stats",
764
+ query={"from": from_, "to": to, "project": project, "timezone": timezone, "tools": tools},
765
+ extra_headers=extra_headers,
766
+ extra_query=extra_query,
767
+ extra_body=extra_body,
768
+ timeout=timeout,
769
+ ),
770
+ response_type=SessionStatsInfo,
771
+ unwrap=True,
772
+ ),
773
+ )
774
+
775
+ def create(
776
+ self,
777
+ *,
778
+ id: SessionID | NotGiven | None = NOT_GIVEN,
779
+ parent_id: SessionID | NotGiven | None = NOT_GIVEN,
780
+ title: str | NotGiven | None = NOT_GIVEN,
781
+ agent: AgentID | NotGiven | None = NOT_GIVEN,
782
+ model: ModelRef | NotGiven | None = NOT_GIVEN,
783
+ location: LocationPublicRef | NotGiven | None = NOT_GIVEN,
784
+ metadata: SessionMetadata | NotGiven | None = NOT_GIVEN,
785
+ permissions: PermissionRuleset | NotGiven | None = NOT_GIVEN,
786
+ extra_headers: Headers | None = None,
787
+ extra_query: Query | None = None,
788
+ extra_body: Body | None = None,
789
+ timeout: Timeout | NotGiven = NOT_GIVEN,
790
+ ) -> SessionInfo:
791
+ """Create session.
792
+
793
+ Create a session at the requested location. A parentID creates a linked child session at its parent's location.
794
+
795
+ Raises:
796
+ InvalidRequestError
797
+ UnauthorizedError
798
+ SessionNotFoundError
799
+
800
+ ``POST /api/session``
801
+ """
802
+ return cast(
803
+ "SessionInfo",
804
+ self._client.request(
805
+ RequestOptions(
806
+ method="POST",
807
+ path="/api/session",
808
+ body={
809
+ "id": id,
810
+ "parentID": parent_id,
811
+ "title": title,
812
+ "agent": agent,
813
+ "model": model,
814
+ "location": self._location(location),
815
+ "metadata": metadata,
816
+ "permissions": permissions,
817
+ },
818
+ extra_headers=extra_headers,
819
+ extra_query=extra_query,
820
+ extra_body=extra_body,
821
+ timeout=timeout,
822
+ ),
823
+ response_type=SessionInfo,
824
+ unwrap=True,
825
+ ),
826
+ )
827
+
828
+ def import_(
829
+ self,
830
+ *,
831
+ info: SessionInfo,
832
+ messages: Sequence[Any],
833
+ location: LocationPublicRef | NotGiven | None = NOT_GIVEN,
834
+ extra_headers: Headers | None = None,
835
+ extra_query: Query | None = None,
836
+ extra_body: Body | None = None,
837
+ timeout: Timeout | NotGiven = NOT_GIVEN,
838
+ ) -> SessionInfo:
839
+ """Import session.
840
+
841
+ Import a projected session transcript at the requested location. Accepts transcripts exported by earlier releases. If parentID is supplied, the parent session must already exist; import parents before children.
842
+
843
+ This endpoint is experimental in OpenCode and may change without notice.
844
+
845
+ Raises:
846
+ InvalidRequestError
847
+ UnauthorizedError
848
+ SessionNotFoundError
849
+ ConflictError
850
+
851
+ ``POST /api/experimental/session/import``
852
+ """
853
+ return cast(
854
+ "SessionInfo",
855
+ self._client.request(
856
+ RequestOptions(
857
+ method="POST",
858
+ path="/api/experimental/session/import",
859
+ body={"info": info, "messages": messages, "location": self._location(location)},
860
+ extra_headers=extra_headers,
861
+ extra_query=extra_query,
862
+ extra_body=extra_body,
863
+ timeout=timeout,
864
+ ),
865
+ response_type=SessionInfo,
866
+ unwrap=True,
867
+ ),
868
+ )
869
+
870
+ def export(
871
+ self,
872
+ session_id: SessionID,
873
+ *,
874
+ sanitize: bool | NotGiven | None = NOT_GIVEN,
875
+ extra_headers: Headers | None = None,
876
+ extra_query: Query | None = None,
877
+ extra_body: Body | None = None,
878
+ timeout: Timeout | NotGiven = NOT_GIVEN,
879
+ ) -> SessionTransferData:
880
+ """Export session.
881
+
882
+ Export a complete projected session transcript.
883
+
884
+ This endpoint is experimental in OpenCode and may change without notice.
885
+
886
+ Raises:
887
+ InvalidRequestError
888
+ UnauthorizedError
889
+ SessionNotFoundError
890
+ UnknownError
891
+
892
+ ``GET /api/experimental/session/:sessionID/export``
893
+ """
894
+ return cast(
895
+ "SessionTransferData",
896
+ self._client.request(
897
+ RequestOptions(
898
+ method="GET",
899
+ path=f"/api/experimental/session/{encode_path_segment(session_id)}/export",
900
+ query={"sanitize": sanitize},
901
+ extra_headers=extra_headers,
902
+ extra_query=extra_query,
903
+ extra_body=extra_body,
904
+ timeout=timeout,
905
+ ),
906
+ response_type=SessionTransferData,
907
+ unwrap=True,
908
+ ),
909
+ )
910
+
911
+ def active(
912
+ self,
913
+ *,
914
+ extra_headers: Headers | None = None,
915
+ extra_query: Query | None = None,
916
+ extra_body: Body | None = None,
917
+ timeout: Timeout | NotGiven = NOT_GIVEN,
918
+ ) -> builtins.dict[str, Any]:
919
+ """List active sessions.
920
+
921
+ Retrieve foreground Session drains currently owned by this OpenCode process. Sessions absent from the result are inactive.
922
+
923
+ Raises:
924
+ InvalidRequestError
925
+ UnauthorizedError
926
+
927
+ ``GET /api/session/active``
928
+ """
929
+ return cast(
930
+ "builtins.dict[str, Any]",
931
+ self._client.request(
932
+ RequestOptions(
933
+ method="GET",
934
+ path="/api/session/active",
935
+ extra_headers=extra_headers,
936
+ extra_query=extra_query,
937
+ extra_body=extra_body,
938
+ timeout=timeout,
939
+ ),
940
+ response_type=builtins.dict[str, Any],
941
+ unwrap=True,
942
+ ),
943
+ )
944
+
945
+ def get(
946
+ self,
947
+ session_id: SessionID,
948
+ *,
949
+ extra_headers: Headers | None = None,
950
+ extra_query: Query | None = None,
951
+ extra_body: Body | None = None,
952
+ timeout: Timeout | NotGiven = NOT_GIVEN,
953
+ ) -> SessionInfo:
954
+ """Get session.
955
+
956
+ Retrieve a session by ID.
957
+
958
+ Raises:
959
+ InvalidRequestError
960
+ UnauthorizedError
961
+ SessionNotFoundError
962
+
963
+ ``GET /api/session/:sessionID``
964
+ """
965
+ return cast(
966
+ "SessionInfo",
967
+ self._client.request(
968
+ RequestOptions(
969
+ method="GET",
970
+ path=f"/api/session/{encode_path_segment(session_id)}",
971
+ extra_headers=extra_headers,
972
+ extra_query=extra_query,
973
+ extra_body=extra_body,
974
+ timeout=timeout,
975
+ ),
976
+ response_type=SessionInfo,
977
+ unwrap=True,
978
+ ),
979
+ )
980
+
981
+ def remove(
982
+ self,
983
+ session_id: SessionID,
984
+ *,
985
+ extra_headers: Headers | None = None,
986
+ extra_query: Query | None = None,
987
+ extra_body: Body | None = None,
988
+ timeout: Timeout | NotGiven = NOT_GIVEN,
989
+ ) -> None:
990
+ """Delete session.
991
+
992
+ Delete a session and its child sessions.
993
+
994
+ Raises:
995
+ InvalidRequestError
996
+ UnauthorizedError
997
+ SessionNotFoundError
998
+
999
+ ``DELETE /api/session/:sessionID``
1000
+ """
1001
+ self._client.request(
1002
+ RequestOptions(
1003
+ method="DELETE",
1004
+ path=f"/api/session/{encode_path_segment(session_id)}",
1005
+ extra_headers=extra_headers,
1006
+ extra_query=extra_query,
1007
+ extra_body=extra_body,
1008
+ timeout=timeout,
1009
+ ),
1010
+ kind="void",
1011
+ )
1012
+
1013
+ def fork(
1014
+ self,
1015
+ session_id: SessionID,
1016
+ *,
1017
+ before: SessionMessageID | NotGiven | None = NOT_GIVEN,
1018
+ extra_headers: Headers | None = None,
1019
+ extra_query: Query | None = None,
1020
+ extra_body: Body | None = None,
1021
+ timeout: Timeout | NotGiven = NOT_GIVEN,
1022
+ ) -> SessionInfo:
1023
+ """Fork session.
1024
+
1025
+ Create a child session by copying projected history before a message. Omit before to copy the full history.
1026
+
1027
+ Raises:
1028
+ InvalidRequestError
1029
+ UnauthorizedError
1030
+ SessionNotFoundError
1031
+ MessageNotFoundError
1032
+ LocationNotFoundError
1033
+
1034
+ ``POST /api/session/:sessionID/fork``
1035
+ """
1036
+ return cast(
1037
+ "SessionInfo",
1038
+ self._client.request(
1039
+ RequestOptions(
1040
+ method="POST",
1041
+ path=f"/api/session/{encode_path_segment(session_id)}/fork",
1042
+ body={"before": before},
1043
+ extra_headers=extra_headers,
1044
+ extra_query=extra_query,
1045
+ extra_body=extra_body,
1046
+ timeout=timeout,
1047
+ ),
1048
+ response_type=SessionInfo,
1049
+ unwrap=True,
1050
+ ),
1051
+ )
1052
+
1053
+ def switch_agent(
1054
+ self,
1055
+ session_id: SessionID,
1056
+ *,
1057
+ agent: AgentID,
1058
+ extra_headers: Headers | None = None,
1059
+ extra_query: Query | None = None,
1060
+ extra_body: Body | None = None,
1061
+ timeout: Timeout | NotGiven = NOT_GIVEN,
1062
+ ) -> None:
1063
+ """Switch session agent.
1064
+
1065
+ Switch the agent used by subsequent provider turns.
1066
+
1067
+ Raises:
1068
+ InvalidRequestError
1069
+ UnauthorizedError
1070
+ SessionNotFoundError
1071
+ LocationNotFoundError
1072
+
1073
+ ``POST /api/session/:sessionID/agent``
1074
+ """
1075
+ self._client.request(
1076
+ RequestOptions(
1077
+ method="POST",
1078
+ path=f"/api/session/{encode_path_segment(session_id)}/agent",
1079
+ body={"agent": agent},
1080
+ extra_headers=extra_headers,
1081
+ extra_query=extra_query,
1082
+ extra_body=extra_body,
1083
+ timeout=timeout,
1084
+ ),
1085
+ kind="void",
1086
+ )
1087
+
1088
+ def switch_model(
1089
+ self,
1090
+ session_id: SessionID,
1091
+ *,
1092
+ model: ModelRef,
1093
+ extra_headers: Headers | None = None,
1094
+ extra_query: Query | None = None,
1095
+ extra_body: Body | None = None,
1096
+ timeout: Timeout | NotGiven = NOT_GIVEN,
1097
+ ) -> None:
1098
+ """Switch session model.
1099
+
1100
+ Switch the model used by subsequent provider turns.
1101
+
1102
+ Raises:
1103
+ InvalidRequestError
1104
+ UnauthorizedError
1105
+ SessionNotFoundError
1106
+ LocationNotFoundError
1107
+
1108
+ ``POST /api/session/:sessionID/model``
1109
+ """
1110
+ self._client.request(
1111
+ RequestOptions(
1112
+ method="POST",
1113
+ path=f"/api/session/{encode_path_segment(session_id)}/model",
1114
+ body={"model": model},
1115
+ extra_headers=extra_headers,
1116
+ extra_query=extra_query,
1117
+ extra_body=extra_body,
1118
+ timeout=timeout,
1119
+ ),
1120
+ kind="void",
1121
+ )
1122
+
1123
+ def update(
1124
+ self,
1125
+ session_id: SessionID,
1126
+ *,
1127
+ title: str | NotGiven | None = NOT_GIVEN,
1128
+ metadata: SessionMetadata | NotGiven | None = NOT_GIVEN,
1129
+ permissions: PermissionRuleset | NotGiven | None = NOT_GIVEN,
1130
+ archived: bool | NotGiven | None = NOT_GIVEN,
1131
+ extra_headers: Headers | None = None,
1132
+ extra_query: Query | None = None,
1133
+ extra_body: Body | None = None,
1134
+ timeout: Timeout | NotGiven = NOT_GIVEN,
1135
+ ) -> None:
1136
+ """Update session.
1137
+
1138
+ Update mutable session properties.
1139
+
1140
+ Args:
1141
+ archived: Archive the session with true or restore it with false. Repeating the current state is a no-op.
1142
+
1143
+ Raises:
1144
+ InvalidRequestError
1145
+ UnauthorizedError
1146
+ SessionNotFoundError
1147
+ LocationNotFoundError
1148
+
1149
+ ``PATCH /api/session/:sessionID``
1150
+ """
1151
+ self._client.request(
1152
+ RequestOptions(
1153
+ method="PATCH",
1154
+ path=f"/api/session/{encode_path_segment(session_id)}",
1155
+ body={"title": title, "metadata": metadata, "permissions": permissions, "archived": archived},
1156
+ extra_headers=extra_headers,
1157
+ extra_query=extra_query,
1158
+ extra_body=extra_body,
1159
+ timeout=timeout,
1160
+ ),
1161
+ kind="void",
1162
+ )
1163
+
1164
+ def move(
1165
+ self,
1166
+ session_id: SessionID,
1167
+ *,
1168
+ directory: AbsolutePath,
1169
+ delivery: SessionInboxDelivery | NotGiven | None = NOT_GIVEN,
1170
+ extra_headers: Headers | None = None,
1171
+ extra_query: Query | None = None,
1172
+ extra_body: Body | None = None,
1173
+ timeout: Timeout | NotGiven = NOT_GIVEN,
1174
+ ) -> None:
1175
+ """Move session.
1176
+
1177
+ Move a session to another project directory at the requested delivery boundary.
1178
+
1179
+ Raises:
1180
+ InvalidRequestError
1181
+ UnauthorizedError
1182
+ SessionNotFoundError
1183
+
1184
+ ``POST /api/session/:sessionID/move``
1185
+ """
1186
+ self._client.request(
1187
+ RequestOptions(
1188
+ method="POST",
1189
+ path=f"/api/session/{encode_path_segment(session_id)}/move",
1190
+ body={"directory": directory, "delivery": delivery},
1191
+ extra_headers=extra_headers,
1192
+ extra_query=extra_query,
1193
+ extra_body=extra_body,
1194
+ timeout=timeout,
1195
+ ),
1196
+ kind="void",
1197
+ )
1198
+
1199
+ def prompt(
1200
+ self,
1201
+ session_id: SessionID,
1202
+ *,
1203
+ text: str,
1204
+ id: SessionMessageID | NotGiven | None = NOT_GIVEN,
1205
+ files: Sequence[PromptInputFileAttachment] | NotGiven = NOT_GIVEN,
1206
+ agents: Sequence[PromptAgentAttachment] | NotGiven = NOT_GIVEN,
1207
+ skills: Sequence[PromptInputSkillAttachment] | NotGiven = NOT_GIVEN,
1208
+ metadata: Mapping[str, Any] | NotGiven = NOT_GIVEN,
1209
+ delivery: SessionInboxDelivery | NotGiven | None = NOT_GIVEN,
1210
+ resume: bool | NotGiven | None = NOT_GIVEN,
1211
+ extra_headers: Headers | None = None,
1212
+ extra_query: Query | None = None,
1213
+ extra_body: Body | None = None,
1214
+ timeout: Timeout | NotGiven = NOT_GIVEN,
1215
+ ) -> SessionInboxUser:
1216
+ """Send message.
1217
+
1218
+ Durably admit one session input and schedule agent-loop execution unless resume is false.
1219
+
1220
+ Raises:
1221
+ InvalidRequestError
1222
+ UnauthorizedError
1223
+ SessionNotFoundError
1224
+ LocationNotFoundError
1225
+ ConflictError
1226
+
1227
+ ``POST /api/session/:sessionID/prompt``
1228
+ """
1229
+ return cast(
1230
+ "SessionInboxUser",
1231
+ self._client.request(
1232
+ RequestOptions(
1233
+ method="POST",
1234
+ path=f"/api/session/{encode_path_segment(session_id)}/prompt",
1235
+ body={
1236
+ "id": id,
1237
+ "text": text,
1238
+ "files": files,
1239
+ "agents": agents,
1240
+ "skills": skills,
1241
+ "metadata": metadata,
1242
+ "delivery": delivery,
1243
+ "resume": resume,
1244
+ },
1245
+ extra_headers=extra_headers,
1246
+ extra_query=extra_query,
1247
+ extra_body=extra_body,
1248
+ timeout=timeout,
1249
+ ),
1250
+ response_type=SessionInboxUser,
1251
+ unwrap=True,
1252
+ ),
1253
+ )
1254
+
1255
+ def command(
1256
+ self,
1257
+ session_id: SessionID,
1258
+ *,
1259
+ name: str,
1260
+ text: str,
1261
+ files: Sequence[PromptInputFileAttachment] | NotGiven = NOT_GIVEN,
1262
+ agents: Sequence[PromptAgentAttachment] | NotGiven = NOT_GIVEN,
1263
+ skills: Sequence[PromptInputSkillAttachment] | NotGiven = NOT_GIVEN,
1264
+ delivery: SessionInboxDelivery | NotGiven | None = NOT_GIVEN,
1265
+ extra_headers: Headers | None = None,
1266
+ extra_query: Query | None = None,
1267
+ extra_body: Body | None = None,
1268
+ timeout: Timeout | NotGiven = NOT_GIVEN,
1269
+ ) -> None:
1270
+ """Run command.
1271
+
1272
+ Execute a slash command callback immediately.
1273
+
1274
+ Raises:
1275
+ InvalidRequestError
1276
+ UnauthorizedError
1277
+ SessionNotFoundError
1278
+ CommandNotFoundError
1279
+ LocationNotFoundError
1280
+ CommandExecutionError
1281
+
1282
+ ``POST /api/session/:sessionID/command``
1283
+ """
1284
+ self._client.request(
1285
+ RequestOptions(
1286
+ method="POST",
1287
+ path=f"/api/session/{encode_path_segment(session_id)}/command",
1288
+ body={
1289
+ "name": name,
1290
+ "text": text,
1291
+ "files": files,
1292
+ "agents": agents,
1293
+ "skills": skills,
1294
+ "delivery": delivery,
1295
+ },
1296
+ extra_headers=extra_headers,
1297
+ extra_query=extra_query,
1298
+ extra_body=extra_body,
1299
+ timeout=timeout,
1300
+ ),
1301
+ kind="void",
1302
+ )
1303
+
1304
+ def skill(
1305
+ self,
1306
+ session_id: SessionID,
1307
+ *,
1308
+ id: SkillID,
1309
+ resume: bool | NotGiven | None = NOT_GIVEN,
1310
+ extra_headers: Headers | None = None,
1311
+ extra_query: Query | None = None,
1312
+ extra_body: Body | None = None,
1313
+ timeout: Timeout | NotGiven = NOT_GIVEN,
1314
+ ) -> None:
1315
+ """Activate skill.
1316
+
1317
+ Activate a skill for a session by appending a skill message and resuming execution.
1318
+
1319
+ This endpoint is experimental in OpenCode and may change without notice.
1320
+
1321
+ Raises:
1322
+ InvalidRequestError
1323
+ UnauthorizedError
1324
+ SessionNotFoundError
1325
+ SkillNotFoundError
1326
+ LocationNotFoundError
1327
+
1328
+ ``POST /api/experimental/session/:sessionID/skill``
1329
+ """
1330
+ self._client.request(
1331
+ RequestOptions(
1332
+ method="POST",
1333
+ path=f"/api/experimental/session/{encode_path_segment(session_id)}/skill",
1334
+ body={"id": id, "resume": resume},
1335
+ extra_headers=extra_headers,
1336
+ extra_query=extra_query,
1337
+ extra_body=extra_body,
1338
+ timeout=timeout,
1339
+ ),
1340
+ kind="void",
1341
+ )
1342
+
1343
+ def synthetic(
1344
+ self,
1345
+ session_id: SessionID,
1346
+ *,
1347
+ text: str,
1348
+ id: SessionMessageID | NotGiven | None = NOT_GIVEN,
1349
+ description: str | NotGiven | None = NOT_GIVEN,
1350
+ metadata: Mapping[str, Any] | NotGiven = NOT_GIVEN,
1351
+ delivery: SessionInboxDelivery | NotGiven | None = NOT_GIVEN,
1352
+ resume: bool | NotGiven | None = NOT_GIVEN,
1353
+ extra_headers: Headers | None = None,
1354
+ extra_query: Query | None = None,
1355
+ extra_body: Body | None = None,
1356
+ timeout: Timeout | NotGiven = NOT_GIVEN,
1357
+ ) -> SessionInboxSynthetic:
1358
+ """Add synthetic message.
1359
+
1360
+ Durably admit synthetic session input and schedule execution unless resume is false.
1361
+
1362
+ Raises:
1363
+ InvalidRequestError
1364
+ UnauthorizedError
1365
+ SessionNotFoundError
1366
+ LocationNotFoundError
1367
+ ConflictError
1368
+
1369
+ ``POST /api/session/:sessionID/synthetic``
1370
+ """
1371
+ return cast(
1372
+ "SessionInboxSynthetic",
1373
+ self._client.request(
1374
+ RequestOptions(
1375
+ method="POST",
1376
+ path=f"/api/session/{encode_path_segment(session_id)}/synthetic",
1377
+ body={
1378
+ "id": id,
1379
+ "text": text,
1380
+ "description": description,
1381
+ "metadata": metadata,
1382
+ "delivery": delivery,
1383
+ "resume": resume,
1384
+ },
1385
+ extra_headers=extra_headers,
1386
+ extra_query=extra_query,
1387
+ extra_body=extra_body,
1388
+ timeout=timeout,
1389
+ ),
1390
+ response_type=SessionInboxSynthetic,
1391
+ unwrap=True,
1392
+ ),
1393
+ )
1394
+
1395
+ def shell(
1396
+ self,
1397
+ session_id: SessionID,
1398
+ *,
1399
+ command: str,
1400
+ id: SessionMessageID | NotGiven | None = NOT_GIVEN,
1401
+ extra_headers: Headers | None = None,
1402
+ extra_query: Query | None = None,
1403
+ extra_body: Body | None = None,
1404
+ timeout: Timeout | NotGiven = NOT_GIVEN,
1405
+ ) -> None:
1406
+ """Run shell command.
1407
+
1408
+ Execute one shell command in the session's working directory. Emits a shell.started event before execution and a shell.ended event with the merged output after.
1409
+
1410
+ Raises:
1411
+ InvalidRequestError
1412
+ UnauthorizedError
1413
+ SessionNotFoundError
1414
+ LocationNotFoundError
1415
+
1416
+ ``POST /api/session/:sessionID/shell``
1417
+ """
1418
+ self._client.request(
1419
+ RequestOptions(
1420
+ method="POST",
1421
+ path=f"/api/session/{encode_path_segment(session_id)}/shell",
1422
+ body={"id": id, "command": command},
1423
+ extra_headers=extra_headers,
1424
+ extra_query=extra_query,
1425
+ extra_body=extra_body,
1426
+ timeout=timeout,
1427
+ ),
1428
+ kind="void",
1429
+ )
1430
+
1431
+ def compact(
1432
+ self,
1433
+ session_id: SessionID,
1434
+ *,
1435
+ id: SessionMessageID | NotGiven | None = NOT_GIVEN,
1436
+ delivery: SessionInboxDelivery | NotGiven | None = NOT_GIVEN,
1437
+ extra_headers: Headers | None = None,
1438
+ extra_query: Query | None = None,
1439
+ extra_body: Body | None = None,
1440
+ timeout: Timeout | NotGiven = NOT_GIVEN,
1441
+ ) -> SessionInboxCompaction:
1442
+ """Compact session.
1443
+
1444
+ Durably admit a session compaction request. Steers by default: it runs at the next step boundary instead of waiting behind queued prompts.
1445
+
1446
+ Raises:
1447
+ InvalidRequestError
1448
+ UnauthorizedError
1449
+ SessionNotFoundError
1450
+ LocationNotFoundError
1451
+ ConflictError
1452
+
1453
+ ``POST /api/session/:sessionID/compact``
1454
+ """
1455
+ return cast(
1456
+ "SessionInboxCompaction",
1457
+ self._client.request(
1458
+ RequestOptions(
1459
+ method="POST",
1460
+ path=f"/api/session/{encode_path_segment(session_id)}/compact",
1461
+ body={"id": id, "delivery": delivery},
1462
+ extra_headers=extra_headers,
1463
+ extra_query=extra_query,
1464
+ extra_body=extra_body,
1465
+ timeout=timeout,
1466
+ ),
1467
+ response_type=SessionInboxCompaction,
1468
+ unwrap=True,
1469
+ ),
1470
+ )
1471
+
1472
+ def wait(
1473
+ self,
1474
+ session_id: SessionID,
1475
+ *,
1476
+ extra_headers: Headers | None = None,
1477
+ extra_query: Query | None = None,
1478
+ extra_body: Body | None = None,
1479
+ timeout: Timeout | NotGiven = NOT_GIVEN,
1480
+ ) -> None:
1481
+ """Wait for session.
1482
+
1483
+ Wait for a session agent loop to become idle.
1484
+
1485
+ This endpoint is experimental in OpenCode and may change without notice.
1486
+
1487
+ Raises:
1488
+ InvalidRequestError
1489
+ UnauthorizedError
1490
+ SessionNotFoundError
1491
+ LocationNotFoundError
1492
+ ServiceUnavailableError
1493
+
1494
+ ``POST /api/experimental/session/:sessionID/wait``
1495
+ """
1496
+ self._client.request(
1497
+ RequestOptions(
1498
+ method="POST",
1499
+ path=f"/api/experimental/session/{encode_path_segment(session_id)}/wait",
1500
+ extra_headers=extra_headers,
1501
+ extra_query=extra_query,
1502
+ extra_body=extra_body,
1503
+ timeout=timeout,
1504
+ ),
1505
+ kind="void",
1506
+ )
1507
+
1508
+ def context(
1509
+ self,
1510
+ session_id: SessionID,
1511
+ *,
1512
+ extra_headers: Headers | None = None,
1513
+ extra_query: Query | None = None,
1514
+ extra_body: Body | None = None,
1515
+ timeout: Timeout | NotGiven = NOT_GIVEN,
1516
+ ) -> builtins.list[SessionMessageInfo]:
1517
+ """Get session context.
1518
+
1519
+ Retrieve the active context messages for a session (all messages after the last compaction).
1520
+
1521
+ Raises:
1522
+ InvalidRequestError
1523
+ UnauthorizedError
1524
+ SessionNotFoundError
1525
+ UnknownError
1526
+
1527
+ ``GET /api/session/:sessionID/context``
1528
+ """
1529
+ return cast(
1530
+ "builtins.list[SessionMessageInfo]",
1531
+ self._client.request(
1532
+ RequestOptions(
1533
+ method="GET",
1534
+ path=f"/api/session/{encode_path_segment(session_id)}/context",
1535
+ extra_headers=extra_headers,
1536
+ extra_query=extra_query,
1537
+ extra_body=extra_body,
1538
+ timeout=timeout,
1539
+ ),
1540
+ response_type=builtins.list[SessionMessageInfo],
1541
+ unwrap=True,
1542
+ ),
1543
+ )
1544
+
1545
+ def diff(
1546
+ self,
1547
+ session_id: SessionID,
1548
+ *,
1549
+ from_: SessionMessageID | NotGiven | None = NOT_GIVEN,
1550
+ to: SessionMessageID | NotGiven | None = NOT_GIVEN,
1551
+ context: int | NotGiven | None = NOT_GIVEN,
1552
+ extra_headers: Headers | None = None,
1553
+ extra_query: Query | None = None,
1554
+ extra_body: Body | None = None,
1555
+ timeout: Timeout | NotGiven = NOT_GIVEN,
1556
+ ) -> builtins.list[FileDiffInfo]:
1557
+ """Diff session turns.
1558
+
1559
+ Structured per-file diffs of the files a turn changed. A turn runs from the first prompt after the session was last idle until its next idle marker, so prompts steered in while it was busy belong to the same turn; `to` extends the range through a later turn. Compares the range's first recorded snapshot with its last; a step still running in the active session compares against the working copy. Ranges that span a location change are rejected. In sessions without any idle marker, a prompt's turn spans until the next user message.
1560
+
1561
+ Args:
1562
+ from_: User message whose turn to diff. Defaults to the turn of the newest user message.
1563
+ to: Later user message whose turn ends the range. Defaults to the turn of `from` alone.
1564
+ context: Unchanged lines around each hunk. Omit for full-file patches.
1565
+
1566
+ Raises:
1567
+ InvalidRequestError
1568
+ UnauthorizedError
1569
+ MessageNotFoundError
1570
+ SessionNotFoundError
1571
+ LocationNotFoundError
1572
+ UnknownError
1573
+
1574
+ ``GET /api/session/:sessionID/diff``
1575
+ """
1576
+ return cast(
1577
+ "builtins.list[FileDiffInfo]",
1578
+ self._client.request(
1579
+ RequestOptions(
1580
+ method="GET",
1581
+ path=f"/api/session/{encode_path_segment(session_id)}/diff",
1582
+ query={"from": from_, "to": to, "context": context},
1583
+ extra_headers=extra_headers,
1584
+ extra_query=extra_query,
1585
+ extra_body=extra_body,
1586
+ timeout=timeout,
1587
+ ),
1588
+ response_type=builtins.list[FileDiffInfo],
1589
+ unwrap=True,
1590
+ ),
1591
+ )
1592
+
1593
+ def generate(
1594
+ self,
1595
+ session_id: SessionID,
1596
+ *,
1597
+ prompt: str,
1598
+ extra_headers: Headers | None = None,
1599
+ extra_query: Query | None = None,
1600
+ extra_body: Body | None = None,
1601
+ timeout: Timeout | NotGiven = NOT_GIVEN,
1602
+ ) -> SessionGenerateResponseData:
1603
+ """Generate text from session context.
1604
+
1605
+ Generate transient text from the current session context without mutating session history.
1606
+
1607
+ Raises:
1608
+ InvalidRequestError
1609
+ UnauthorizedError
1610
+ SessionNotFoundError
1611
+ LocationNotFoundError
1612
+ ServiceUnavailableError
1613
+
1614
+ ``POST /api/session/:sessionID/generate``
1615
+ """
1616
+ return cast(
1617
+ "SessionGenerateResponseData",
1618
+ self._client.request(
1619
+ RequestOptions(
1620
+ method="POST",
1621
+ path=f"/api/session/{encode_path_segment(session_id)}/generate",
1622
+ body={"prompt": prompt},
1623
+ extra_headers=extra_headers,
1624
+ extra_query=extra_query,
1625
+ extra_body=extra_body,
1626
+ timeout=timeout,
1627
+ ),
1628
+ response_type=SessionGenerateResponseData,
1629
+ unwrap=True,
1630
+ ),
1631
+ )
1632
+
1633
+ def log(
1634
+ self,
1635
+ session_id: SessionID,
1636
+ *,
1637
+ after: EventSeq | NotGiven | None = NOT_GIVEN,
1638
+ follow: bool | NotGiven | None = NOT_GIVEN,
1639
+ extra_headers: Headers | None = None,
1640
+ extra_query: Query | None = None,
1641
+ extra_body: Body | None = None,
1642
+ timeout: Timeout | NotGiven = NOT_GIVEN,
1643
+ ) -> Stream[SessionLogItem]:
1644
+ """Read the session log.
1645
+
1646
+ Experimental durable session event log. Reads events after an exclusive aggregate sequence and continues with live events when follow=true.
1647
+
1648
+ This endpoint is experimental in OpenCode and may change without notice.
1649
+
1650
+ Raises:
1651
+ InvalidRequestError
1652
+ UnauthorizedError
1653
+ SessionNotFoundError
1654
+
1655
+ ``GET /api/experimental/session/:sessionID/log``
1656
+ """
1657
+ return self._client.stream(
1658
+ RequestOptions(
1659
+ method="GET",
1660
+ path=f"/api/experimental/session/{encode_path_segment(session_id)}/log",
1661
+ query={"after": after, "follow": follow},
1662
+ extra_headers=extra_headers,
1663
+ extra_query=extra_query,
1664
+ extra_body=extra_body,
1665
+ timeout=timeout,
1666
+ ),
1667
+ item_type=SessionLogItem,
1668
+ )
1669
+
1670
+ def interrupt(
1671
+ self,
1672
+ session_id: SessionID,
1673
+ *,
1674
+ resume: bool | NotGiven | None = NOT_GIVEN,
1675
+ extra_headers: Headers | None = None,
1676
+ extra_query: Query | None = None,
1677
+ extra_body: Body | None = None,
1678
+ timeout: Timeout | NotGiven = NOT_GIVEN,
1679
+ ) -> SessionInterruptResponse:
1680
+ """Interrupt session execution.
1681
+
1682
+ Interrupt active execution owned by this OpenCode process. Returns interrupted=true when an active execution was interrupted and false for the idle no-op. When resume=true, execution resumes pending steering input and next-in-line control items (manual compaction, moves) while queued prompts remain parked.
1683
+
1684
+ Raises:
1685
+ InvalidRequestError
1686
+ UnauthorizedError
1687
+ SessionNotFoundError
1688
+ LocationNotFoundError
1689
+
1690
+ ``POST /api/session/:sessionID/interrupt``
1691
+ """
1692
+ return cast(
1693
+ "SessionInterruptResponse",
1694
+ self._client.request(
1695
+ RequestOptions(
1696
+ method="POST",
1697
+ path=f"/api/session/{encode_path_segment(session_id)}/interrupt",
1698
+ query={"resume": resume},
1699
+ extra_headers=extra_headers,
1700
+ extra_query=extra_query,
1701
+ extra_body=extra_body,
1702
+ timeout=timeout,
1703
+ ),
1704
+ response_type=SessionInterruptResponse,
1705
+ ),
1706
+ )
1707
+
1708
+ def background(
1709
+ self,
1710
+ session_id: SessionID,
1711
+ *,
1712
+ extra_headers: Headers | None = None,
1713
+ extra_query: Query | None = None,
1714
+ extra_body: Body | None = None,
1715
+ timeout: Timeout | NotGiven = NOT_GIVEN,
1716
+ ) -> None:
1717
+ """Background blocking session tools.
1718
+
1719
+ Move active foreground backgroundable tools for this session into background observation. Idle requests are a no-op.
1720
+
1721
+ Raises:
1722
+ InvalidRequestError
1723
+ UnauthorizedError
1724
+ SessionNotFoundError
1725
+ LocationNotFoundError
1726
+
1727
+ ``POST /api/session/:sessionID/background``
1728
+ """
1729
+ self._client.request(
1730
+ RequestOptions(
1731
+ method="POST",
1732
+ path=f"/api/session/{encode_path_segment(session_id)}/background",
1733
+ extra_headers=extra_headers,
1734
+ extra_query=extra_query,
1735
+ extra_body=extra_body,
1736
+ timeout=timeout,
1737
+ ),
1738
+ kind="void",
1739
+ )
1740
+
1741
+ def environment(
1742
+ self,
1743
+ session_id: SessionID,
1744
+ *,
1745
+ variables: Mapping[str, str],
1746
+ extra_headers: Headers | None = None,
1747
+ extra_query: Query | None = None,
1748
+ extra_body: Body | None = None,
1749
+ timeout: Timeout | NotGiven = NOT_GIVEN,
1750
+ ) -> None:
1751
+ """Set session environment.
1752
+
1753
+ Replace the process environment used by local shell commands for this session.
1754
+
1755
+ Raises:
1756
+ InvalidRequestError
1757
+ UnauthorizedError
1758
+ SessionNotFoundError
1759
+
1760
+ ``PUT /api/session/:sessionID/environment``
1761
+ """
1762
+ self._client.request(
1763
+ RequestOptions(
1764
+ method="PUT",
1765
+ path=f"/api/session/{encode_path_segment(session_id)}/environment",
1766
+ body={"variables": variables},
1767
+ extra_headers=extra_headers,
1768
+ extra_query=extra_query,
1769
+ extra_body=extra_body,
1770
+ timeout=timeout,
1771
+ ),
1772
+ kind="void",
1773
+ )
1774
+
1775
+ def view(
1776
+ self,
1777
+ session_id: SessionID,
1778
+ *,
1779
+ idle: float,
1780
+ extra_headers: Headers | None = None,
1781
+ extra_query: Query | None = None,
1782
+ extra_body: Body | None = None,
1783
+ timeout: Timeout | NotGiven = NOT_GIVEN,
1784
+ ) -> None:
1785
+ """View session.
1786
+
1787
+ Mark the idle transition observed by the viewer as viewed.
1788
+
1789
+ Raises:
1790
+ InvalidRequestError
1791
+ UnauthorizedError
1792
+ SessionNotFoundError
1793
+
1794
+ ``POST /api/session/:sessionID/view``
1795
+ """
1796
+ self._client.request(
1797
+ RequestOptions(
1798
+ method="POST",
1799
+ path=f"/api/session/{encode_path_segment(session_id)}/view",
1800
+ body={"idle": idle},
1801
+ extra_headers=extra_headers,
1802
+ extra_query=extra_query,
1803
+ extra_body=extra_body,
1804
+ timeout=timeout,
1805
+ ),
1806
+ kind="void",
1807
+ )
1808
+
1809
+
1810
+ class AsyncSessionRevertResource(AsyncAPIResource):
1811
+ """Operations under ``client.session.revert`` (OpenCode ``session.revert``)."""
1812
+
1813
+ async def stage(
1814
+ self,
1815
+ session_id: SessionID,
1816
+ *,
1817
+ message_id: SessionMessageID,
1818
+ files: bool | NotGiven | None = NOT_GIVEN,
1819
+ extra_headers: Headers | None = None,
1820
+ extra_query: Query | None = None,
1821
+ extra_body: Body | None = None,
1822
+ timeout: Timeout | NotGiven = NOT_GIVEN,
1823
+ ) -> SessionRevert:
1824
+ """Stage session revert.
1825
+
1826
+ Stage or move a reversible session boundary and optionally apply its file changes.
1827
+
1828
+ Raises:
1829
+ InvalidRequestError
1830
+ UnauthorizedError
1831
+ MessageNotFoundError
1832
+ SessionNotFoundError
1833
+ LocationNotFoundError
1834
+ SessionBusyError
1835
+ UnknownError
1836
+
1837
+ ``POST /api/session/:sessionID/revert/stage``
1838
+ """
1839
+ return cast(
1840
+ "SessionRevert",
1841
+ await self._client.request(
1842
+ RequestOptions(
1843
+ method="POST",
1844
+ path=f"/api/session/{encode_path_segment(session_id)}/revert/stage",
1845
+ body={"messageID": message_id, "files": files},
1846
+ extra_headers=extra_headers,
1847
+ extra_query=extra_query,
1848
+ extra_body=extra_body,
1849
+ timeout=timeout,
1850
+ ),
1851
+ response_type=SessionRevert,
1852
+ unwrap=True,
1853
+ ),
1854
+ )
1855
+
1856
+ async def clear(
1857
+ self,
1858
+ session_id: SessionID,
1859
+ *,
1860
+ extra_headers: Headers | None = None,
1861
+ extra_query: Query | None = None,
1862
+ extra_body: Body | None = None,
1863
+ timeout: Timeout | NotGiven = NOT_GIVEN,
1864
+ ) -> None:
1865
+ """Clear staged revert.
1866
+
1867
+ Raises:
1868
+ InvalidRequestError
1869
+ UnauthorizedError
1870
+ SessionNotFoundError
1871
+ LocationNotFoundError
1872
+ SessionBusyError
1873
+ UnknownError
1874
+
1875
+ ``DELETE /api/session/:sessionID/revert``
1876
+ """
1877
+ await self._client.request(
1878
+ RequestOptions(
1879
+ method="DELETE",
1880
+ path=f"/api/session/{encode_path_segment(session_id)}/revert",
1881
+ extra_headers=extra_headers,
1882
+ extra_query=extra_query,
1883
+ extra_body=extra_body,
1884
+ timeout=timeout,
1885
+ ),
1886
+ kind="void",
1887
+ )
1888
+
1889
+ async def commit(
1890
+ self,
1891
+ session_id: SessionID,
1892
+ *,
1893
+ extra_headers: Headers | None = None,
1894
+ extra_query: Query | None = None,
1895
+ extra_body: Body | None = None,
1896
+ timeout: Timeout | NotGiven = NOT_GIVEN,
1897
+ ) -> None:
1898
+ """Commit staged revert.
1899
+
1900
+ Raises:
1901
+ InvalidRequestError
1902
+ UnauthorizedError
1903
+ SessionNotFoundError
1904
+ LocationNotFoundError
1905
+ SessionBusyError
1906
+
1907
+ ``POST /api/session/:sessionID/revert/commit``
1908
+ """
1909
+ await self._client.request(
1910
+ RequestOptions(
1911
+ method="POST",
1912
+ path=f"/api/session/{encode_path_segment(session_id)}/revert/commit",
1913
+ extra_headers=extra_headers,
1914
+ extra_query=extra_query,
1915
+ extra_body=extra_body,
1916
+ timeout=timeout,
1917
+ ),
1918
+ kind="void",
1919
+ )
1920
+
1921
+
1922
+ class AsyncSessionInboxResource(AsyncAPIResource):
1923
+ """Operations under ``client.session.inbox`` (OpenCode ``session.inbox``)."""
1924
+
1925
+ async def list(
1926
+ self,
1927
+ session_id: SessionID,
1928
+ *,
1929
+ extra_headers: Headers | None = None,
1930
+ extra_query: Query | None = None,
1931
+ extra_body: Body | None = None,
1932
+ timeout: Timeout | NotGiven = NOT_GIVEN,
1933
+ ) -> builtins.list[SessionInboxInfo]:
1934
+ """List session inbox.
1935
+
1936
+ List durable enqueued session work not yet delivered, ordered by enqueue sequence. Includes user, synthetic, compaction, and move items.
1937
+
1938
+ Raises:
1939
+ InvalidRequestError
1940
+ UnauthorizedError
1941
+ SessionNotFoundError
1942
+
1943
+ ``GET /api/session/:sessionID/inbox``
1944
+ """
1945
+ return cast(
1946
+ "builtins.list[SessionInboxInfo]",
1947
+ await self._client.request(
1948
+ RequestOptions(
1949
+ method="GET",
1950
+ path=f"/api/session/{encode_path_segment(session_id)}/inbox",
1951
+ extra_headers=extra_headers,
1952
+ extra_query=extra_query,
1953
+ extra_body=extra_body,
1954
+ timeout=timeout,
1955
+ ),
1956
+ response_type=builtins.list[SessionInboxInfo],
1957
+ unwrap=True,
1958
+ ),
1959
+ )
1960
+
1961
+ async def cancel(
1962
+ self,
1963
+ session_id: SessionID,
1964
+ inbox_id: SessionMessageID,
1965
+ *,
1966
+ extra_headers: Headers | None = None,
1967
+ extra_query: Query | None = None,
1968
+ extra_body: Body | None = None,
1969
+ timeout: Timeout | NotGiven = NOT_GIVEN,
1970
+ ) -> None:
1971
+ """Cancel inbox input.
1972
+
1973
+ Cancel an inbox item that has not yet been delivered. Unavailable items are a no-op.
1974
+
1975
+ Raises:
1976
+ InvalidRequestError
1977
+ UnauthorizedError
1978
+ SessionNotFoundError
1979
+
1980
+ ``DELETE /api/session/:sessionID/inbox/:inboxID``
1981
+ """
1982
+ await self._client.request(
1983
+ RequestOptions(
1984
+ method="DELETE",
1985
+ path=f"/api/session/{encode_path_segment(session_id)}/inbox/{encode_path_segment(inbox_id)}",
1986
+ extra_headers=extra_headers,
1987
+ extra_query=extra_query,
1988
+ extra_body=extra_body,
1989
+ timeout=timeout,
1990
+ ),
1991
+ kind="void",
1992
+ )
1993
+
1994
+ async def update(
1995
+ self,
1996
+ session_id: SessionID,
1997
+ inbox_id: SessionMessageID,
1998
+ *,
1999
+ delivery: SessionInboxDelivery,
2000
+ extra_headers: Headers | None = None,
2001
+ extra_query: Query | None = None,
2002
+ extra_body: Body | None = None,
2003
+ timeout: Timeout | NotGiven = NOT_GIVEN,
2004
+ ) -> None:
2005
+ """Update inbox item.
2006
+
2007
+ Change a pending inbox item's delivery mode. Steering wakes session execution.
2008
+
2009
+ Raises:
2010
+ InvalidRequestError
2011
+ UnauthorizedError
2012
+ SessionNotFoundError
2013
+ ConflictError
2014
+
2015
+ ``PATCH /api/session/:sessionID/inbox/:inboxID``
2016
+ """
2017
+ await self._client.request(
2018
+ RequestOptions(
2019
+ method="PATCH",
2020
+ path=f"/api/session/{encode_path_segment(session_id)}/inbox/{encode_path_segment(inbox_id)}",
2021
+ body={"delivery": delivery},
2022
+ extra_headers=extra_headers,
2023
+ extra_query=extra_query,
2024
+ extra_body=extra_body,
2025
+ timeout=timeout,
2026
+ ),
2027
+ kind="void",
2028
+ )
2029
+
2030
+
2031
+ class AsyncSessionInstructionsEntryResource(AsyncAPIResource):
2032
+ """Operations under ``client.session.instructions.entry`` (OpenCode ``session.instructions.entry``)."""
2033
+
2034
+ async def list(
2035
+ self,
2036
+ session_id: SessionID,
2037
+ *,
2038
+ extra_headers: Headers | None = None,
2039
+ extra_query: Query | None = None,
2040
+ extra_body: Body | None = None,
2041
+ timeout: Timeout | NotGiven = NOT_GIVEN,
2042
+ ) -> builtins.list[InstructionEntryInfo]:
2043
+ """List instruction entries.
2044
+
2045
+ List API-managed instruction entries attached to the session.
2046
+
2047
+ This endpoint is experimental in OpenCode and may change without notice.
2048
+
2049
+ Raises:
2050
+ InvalidRequestError
2051
+ UnauthorizedError
2052
+ SessionNotFoundError
2053
+ LocationNotFoundError
2054
+
2055
+ ``GET /api/experimental/session/:sessionID/instructions/entries``
2056
+ """
2057
+ return cast(
2058
+ "builtins.list[InstructionEntryInfo]",
2059
+ await self._client.request(
2060
+ RequestOptions(
2061
+ method="GET",
2062
+ path=f"/api/experimental/session/{encode_path_segment(session_id)}/instructions/entries",
2063
+ extra_headers=extra_headers,
2064
+ extra_query=extra_query,
2065
+ extra_body=extra_body,
2066
+ timeout=timeout,
2067
+ ),
2068
+ response_type=builtins.list[InstructionEntryInfo],
2069
+ unwrap=True,
2070
+ ),
2071
+ )
2072
+
2073
+ async def put(
2074
+ self,
2075
+ session_id: SessionID,
2076
+ key: InstructionEntryKey,
2077
+ *,
2078
+ value: Any,
2079
+ extra_headers: Headers | None = None,
2080
+ extra_query: Query | None = None,
2081
+ extra_body: Body | None = None,
2082
+ timeout: Timeout | NotGiven = NOT_GIVEN,
2083
+ ) -> None:
2084
+ """Put instruction entry.
2085
+
2086
+ Attach or replace one durable instruction entry. Changes announce as updates at the next step boundary.
2087
+
2088
+ This endpoint is experimental in OpenCode and may change without notice.
2089
+
2090
+ Raises:
2091
+ InvalidRequestError
2092
+ UnauthorizedError
2093
+ SessionNotFoundError
2094
+ LocationNotFoundError
2095
+ InstructionEntryValueTooLargeError
2096
+
2097
+ ``PUT /api/experimental/session/:sessionID/instructions/entries/:key``
2098
+ """
2099
+ await self._client.request(
2100
+ RequestOptions(
2101
+ method="PUT",
2102
+ path=f"/api/experimental/session/{encode_path_segment(session_id)}/instructions/entries/{encode_path_segment(key)}",
2103
+ body={"value": value},
2104
+ extra_headers=extra_headers,
2105
+ extra_query=extra_query,
2106
+ extra_body=extra_body,
2107
+ timeout=timeout,
2108
+ ),
2109
+ kind="void",
2110
+ )
2111
+
2112
+ async def remove(
2113
+ self,
2114
+ session_id: SessionID,
2115
+ key: InstructionEntryKey,
2116
+ *,
2117
+ extra_headers: Headers | None = None,
2118
+ extra_query: Query | None = None,
2119
+ extra_body: Body | None = None,
2120
+ timeout: Timeout | NotGiven = NOT_GIVEN,
2121
+ ) -> None:
2122
+ """Remove instruction entry.
2123
+
2124
+ Remove one instruction entry; the removal is announced to the model at the next step boundary.
2125
+
2126
+ This endpoint is experimental in OpenCode and may change without notice.
2127
+
2128
+ Raises:
2129
+ InvalidRequestError
2130
+ UnauthorizedError
2131
+ SessionNotFoundError
2132
+ LocationNotFoundError
2133
+
2134
+ ``DELETE /api/experimental/session/:sessionID/instructions/entries/:key``
2135
+ """
2136
+ await self._client.request(
2137
+ RequestOptions(
2138
+ method="DELETE",
2139
+ path=f"/api/experimental/session/{encode_path_segment(session_id)}/instructions/entries/{encode_path_segment(key)}",
2140
+ extra_headers=extra_headers,
2141
+ extra_query=extra_query,
2142
+ extra_body=extra_body,
2143
+ timeout=timeout,
2144
+ ),
2145
+ kind="void",
2146
+ )
2147
+
2148
+
2149
+ class AsyncSessionInstructionsResource(AsyncAPIResource):
2150
+ """Operations under ``client.session.instructions`` (OpenCode ``session.instructions``)."""
2151
+
2152
+ @cached_property
2153
+ def entry(self) -> AsyncSessionInstructionsEntryResource:
2154
+ return AsyncSessionInstructionsEntryResource(self._client)
2155
+
2156
+
2157
+ class AsyncSessionMessageResource(AsyncAPIResource):
2158
+ """Operations under ``client.session.message`` (OpenCode ``session.message``)."""
2159
+
2160
+ async def get(
2161
+ self,
2162
+ session_id: SessionID,
2163
+ message_id: SessionMessageID,
2164
+ *,
2165
+ extra_headers: Headers | None = None,
2166
+ extra_query: Query | None = None,
2167
+ extra_body: Body | None = None,
2168
+ timeout: Timeout | NotGiven = NOT_GIVEN,
2169
+ ) -> SessionMessageInfo:
2170
+ """Get session message.
2171
+
2172
+ Retrieve one projected message owned by the Session.
2173
+
2174
+ Raises:
2175
+ InvalidRequestError
2176
+ UnauthorizedError
2177
+ SessionNotFoundError
2178
+ MessageNotFoundError
2179
+
2180
+ ``GET /api/session/:sessionID/message/:messageID``
2181
+ """
2182
+ return cast(
2183
+ "SessionMessageInfo",
2184
+ await self._client.request(
2185
+ RequestOptions(
2186
+ method="GET",
2187
+ path=f"/api/session/{encode_path_segment(session_id)}/message/{encode_path_segment(message_id)}",
2188
+ extra_headers=extra_headers,
2189
+ extra_query=extra_query,
2190
+ extra_body=extra_body,
2191
+ timeout=timeout,
2192
+ ),
2193
+ response_type=SessionMessageInfo,
2194
+ unwrap=True,
2195
+ ),
2196
+ )
2197
+
2198
+
2199
+ class AsyncSessionFormResource(AsyncAPIResource):
2200
+ """Operations under ``client.session.form`` (OpenCode ``session.form``)."""
2201
+
2202
+ async def list(
2203
+ self,
2204
+ session_id: str,
2205
+ *,
2206
+ extra_headers: Headers | None = None,
2207
+ extra_query: Query | None = None,
2208
+ extra_body: Body | None = None,
2209
+ timeout: Timeout | NotGiven = NOT_GIVEN,
2210
+ ) -> builtins.list[FormInfo]:
2211
+ """List session forms.
2212
+
2213
+ Retrieve pending forms for a session.
2214
+
2215
+ Raises:
2216
+ InvalidRequestError
2217
+ UnauthorizedError
2218
+ SessionNotFoundError
2219
+ LocationNotFoundError
2220
+
2221
+ ``GET /api/session/:sessionID/form``
2222
+ """
2223
+ return cast(
2224
+ "builtins.list[FormInfo]",
2225
+ await self._client.request(
2226
+ RequestOptions(
2227
+ method="GET",
2228
+ path=f"/api/session/{encode_path_segment(session_id)}/form",
2229
+ extra_headers=extra_headers,
2230
+ extra_query=extra_query,
2231
+ extra_body=extra_body,
2232
+ timeout=timeout,
2233
+ ),
2234
+ response_type=builtins.list[FormInfo],
2235
+ unwrap=True,
2236
+ ),
2237
+ )
2238
+
2239
+ async def create(
2240
+ self,
2241
+ session_id: str,
2242
+ *,
2243
+ title: str,
2244
+ fields: FormFields,
2245
+ id: FormID | NotGiven | None = NOT_GIVEN,
2246
+ metadata: FormMetadata | NotGiven = NOT_GIVEN,
2247
+ extra_headers: Headers | None = None,
2248
+ extra_query: Query | None = None,
2249
+ extra_body: Body | None = None,
2250
+ timeout: Timeout | NotGiven = NOT_GIVEN,
2251
+ ) -> FormInfo:
2252
+ """Create session form.
2253
+
2254
+ Create a form for a session.
2255
+
2256
+ Raises:
2257
+ InvalidRequestError
2258
+ UnauthorizedError
2259
+ SessionNotFoundError
2260
+ LocationNotFoundError
2261
+ ConflictError
2262
+
2263
+ ``POST /api/session/:sessionID/form``
2264
+ """
2265
+ return cast(
2266
+ "FormInfo",
2267
+ await self._client.request(
2268
+ RequestOptions(
2269
+ method="POST",
2270
+ path=f"/api/session/{encode_path_segment(session_id)}/form",
2271
+ body={"id": id, "title": title, "metadata": metadata, "fields": fields},
2272
+ extra_headers=extra_headers,
2273
+ extra_query=extra_query,
2274
+ extra_body=extra_body,
2275
+ timeout=timeout,
2276
+ ),
2277
+ response_type=FormInfo,
2278
+ unwrap=True,
2279
+ ),
2280
+ )
2281
+
2282
+ async def get(
2283
+ self,
2284
+ session_id: str,
2285
+ form_id: FormID,
2286
+ *,
2287
+ extra_headers: Headers | None = None,
2288
+ extra_query: Query | None = None,
2289
+ extra_body: Body | None = None,
2290
+ timeout: Timeout | NotGiven = NOT_GIVEN,
2291
+ ) -> FormDetail:
2292
+ """Get session form.
2293
+
2294
+ Retrieve a form and its current state for a session.
2295
+
2296
+ Raises:
2297
+ InvalidRequestError
2298
+ UnauthorizedError
2299
+ SessionNotFoundError
2300
+ FormNotFoundError
2301
+ LocationNotFoundError
2302
+
2303
+ ``GET /api/session/:sessionID/form/:formID``
2304
+ """
2305
+ return cast(
2306
+ "FormDetail",
2307
+ await self._client.request(
2308
+ RequestOptions(
2309
+ method="GET",
2310
+ path=f"/api/session/{encode_path_segment(session_id)}/form/{encode_path_segment(form_id)}",
2311
+ extra_headers=extra_headers,
2312
+ extra_query=extra_query,
2313
+ extra_body=extra_body,
2314
+ timeout=timeout,
2315
+ ),
2316
+ response_type=FormDetail,
2317
+ unwrap=True,
2318
+ ),
2319
+ )
2320
+
2321
+ async def reply(
2322
+ self,
2323
+ session_id: str,
2324
+ form_id: FormID,
2325
+ *,
2326
+ answer: FormAnswer,
2327
+ extra_headers: Headers | None = None,
2328
+ extra_query: Query | None = None,
2329
+ extra_body: Body | None = None,
2330
+ timeout: Timeout | NotGiven = NOT_GIVEN,
2331
+ ) -> None:
2332
+ """Reply to form.
2333
+
2334
+ Submit an answer to a pending form.
2335
+
2336
+ Raises:
2337
+ FormInvalidAnswerError
2338
+ InvalidRequestError
2339
+ UnauthorizedError
2340
+ SessionNotFoundError
2341
+ FormNotFoundError
2342
+ LocationNotFoundError
2343
+ FormAlreadySettledError
2344
+
2345
+ ``POST /api/session/:sessionID/form/:formID/reply``
2346
+ """
2347
+ await self._client.request(
2348
+ RequestOptions(
2349
+ method="POST",
2350
+ path=f"/api/session/{encode_path_segment(session_id)}/form/{encode_path_segment(form_id)}/reply",
2351
+ body={"answer": answer},
2352
+ extra_headers=extra_headers,
2353
+ extra_query=extra_query,
2354
+ extra_body=extra_body,
2355
+ timeout=timeout,
2356
+ ),
2357
+ kind="void",
2358
+ )
2359
+
2360
+ async def cancel(
2361
+ self,
2362
+ session_id: str,
2363
+ form_id: FormID,
2364
+ *,
2365
+ message: str | NotGiven | None = NOT_GIVEN,
2366
+ extra_headers: Headers | None = None,
2367
+ extra_query: Query | None = None,
2368
+ extra_body: Body | None = None,
2369
+ timeout: Timeout | NotGiven = NOT_GIVEN,
2370
+ ) -> None:
2371
+ """Cancel form.
2372
+
2373
+ Cancel a pending form, optionally telling the asker why it was not answered.
2374
+
2375
+ Raises:
2376
+ InvalidRequestError
2377
+ UnauthorizedError
2378
+ SessionNotFoundError
2379
+ FormNotFoundError
2380
+ LocationNotFoundError
2381
+ FormAlreadySettledError
2382
+
2383
+ ``DELETE /api/session/:sessionID/form/:formID``
2384
+ """
2385
+ await self._client.request(
2386
+ RequestOptions(
2387
+ method="DELETE",
2388
+ path=f"/api/session/{encode_path_segment(session_id)}/form/{encode_path_segment(form_id)}",
2389
+ query={"message": message},
2390
+ extra_headers=extra_headers,
2391
+ extra_query=extra_query,
2392
+ extra_body=extra_body,
2393
+ timeout=timeout,
2394
+ ),
2395
+ kind="void",
2396
+ )
2397
+
2398
+
2399
+ class AsyncSessionResource(AsyncAPIResource):
2400
+ """Operations under ``client.session`` (OpenCode ``session``)."""
2401
+
2402
+ @cached_property
2403
+ def revert(self) -> AsyncSessionRevertResource:
2404
+ return AsyncSessionRevertResource(self._client)
2405
+
2406
+ @cached_property
2407
+ def inbox(self) -> AsyncSessionInboxResource:
2408
+ return AsyncSessionInboxResource(self._client)
2409
+
2410
+ @cached_property
2411
+ def instructions(self) -> AsyncSessionInstructionsResource:
2412
+ return AsyncSessionInstructionsResource(self._client)
2413
+
2414
+ @cached_property
2415
+ def message(self) -> AsyncSessionMessageResource:
2416
+ return AsyncSessionMessageResource(self._client)
2417
+
2418
+ @cached_property
2419
+ def form(self) -> AsyncSessionFormResource:
2420
+ return AsyncSessionFormResource(self._client)
2421
+
2422
+ def list(
2423
+ self,
2424
+ *,
2425
+ limit: int | NotGiven | None = NOT_GIVEN,
2426
+ order: OpenEnum[Literal["asc", "desc"]] | NotGiven | None = NOT_GIVEN,
2427
+ search: str | NotGiven | None = NOT_GIVEN,
2428
+ parent_id: SessionID | NotGiven | None = NOT_GIVEN,
2429
+ archived: bool | NotGiven | None = NOT_GIVEN,
2430
+ directory: AbsolutePath | NotGiven | None = NOT_GIVEN,
2431
+ project: ProjectID | NotGiven | None = NOT_GIVEN,
2432
+ subpath: RelativePath | NotGiven | None = NOT_GIVEN,
2433
+ cursor: SessionsCursor | NotGiven | None = NOT_GIVEN,
2434
+ extra_headers: Headers | None = None,
2435
+ extra_query: Query | None = None,
2436
+ extra_body: Body | None = None,
2437
+ timeout: Timeout | NotGiven = NOT_GIVEN,
2438
+ ) -> AsyncPaginator[SessionInfo]:
2439
+ """List sessions.
2440
+
2441
+ Retrieve sessions in the requested order. Items keep that order across pages; use cursor.next or cursor.previous to move through the ordered list.
2442
+
2443
+ Args:
2444
+ limit: Maximum number of sessions to return. Defaults to the newest 50 sessions.
2445
+ order: Session order for the first page. Use desc for newest first or asc for oldest first.
2446
+ parent_id: Filter by parent session. Use null to return only root sessions.
2447
+ archived: Filter by archive state. Use true to return only archived sessions or false to exclude them. Omit to include both.
2448
+
2449
+ Raises:
2450
+ InvalidCursorError
2451
+ InvalidRequestError
2452
+ UnauthorizedError
2453
+
2454
+ ``GET /api/session``
2455
+ """
2456
+ return self._client.page(
2457
+ RequestOptions(
2458
+ method="GET",
2459
+ path="/api/session",
2460
+ query={
2461
+ "limit": limit,
2462
+ "order": order,
2463
+ "search": search,
2464
+ "parentID": parent_id,
2465
+ "archived": archived,
2466
+ "directory": directory,
2467
+ "project": project,
2468
+ "subpath": subpath,
2469
+ "cursor": cursor,
2470
+ },
2471
+ extra_headers=extra_headers,
2472
+ extra_query=extra_query,
2473
+ extra_body=extra_body,
2474
+ timeout=timeout,
2475
+ ),
2476
+ response_type=SessionsResponse,
2477
+ )
2478
+
2479
+ async def stats(
2480
+ self,
2481
+ *,
2482
+ from_: float | OpenEnum[Literal["Infinity", "-Infinity", "NaN"]] | NotGiven | None = NOT_GIVEN,
2483
+ to: float | OpenEnum[Literal["Infinity", "-Infinity", "NaN"]] | NotGiven | None = NOT_GIVEN,
2484
+ project: ProjectID | NotGiven | None = NOT_GIVEN,
2485
+ timezone: str | NotGiven | None = NOT_GIVEN,
2486
+ tools: OpenEnum[Literal["none", "summary", "detail"]] | NotGiven | None = NOT_GIVEN,
2487
+ extra_headers: Headers | None = None,
2488
+ extra_query: Query | None = None,
2489
+ extra_body: Body | None = None,
2490
+ timeout: Timeout | NotGiven = NOT_GIVEN,
2491
+ ) -> SessionStatsInfo:
2492
+ """Get session statistics.
2493
+
2494
+ Aggregate local session activity, usage, and tool reliability for a time range.
2495
+
2496
+ This endpoint is experimental in OpenCode and may change without notice.
2497
+
2498
+ Raises:
2499
+ InvalidRequestError
2500
+ UnauthorizedError
2501
+
2502
+ ``GET /api/experimental/session/stats``
2503
+ """
2504
+ return cast(
2505
+ "SessionStatsInfo",
2506
+ await self._client.request(
2507
+ RequestOptions(
2508
+ method="GET",
2509
+ path="/api/experimental/session/stats",
2510
+ query={"from": from_, "to": to, "project": project, "timezone": timezone, "tools": tools},
2511
+ extra_headers=extra_headers,
2512
+ extra_query=extra_query,
2513
+ extra_body=extra_body,
2514
+ timeout=timeout,
2515
+ ),
2516
+ response_type=SessionStatsInfo,
2517
+ unwrap=True,
2518
+ ),
2519
+ )
2520
+
2521
+ async def create(
2522
+ self,
2523
+ *,
2524
+ id: SessionID | NotGiven | None = NOT_GIVEN,
2525
+ parent_id: SessionID | NotGiven | None = NOT_GIVEN,
2526
+ title: str | NotGiven | None = NOT_GIVEN,
2527
+ agent: AgentID | NotGiven | None = NOT_GIVEN,
2528
+ model: ModelRef | NotGiven | None = NOT_GIVEN,
2529
+ location: LocationPublicRef | NotGiven | None = NOT_GIVEN,
2530
+ metadata: SessionMetadata | NotGiven | None = NOT_GIVEN,
2531
+ permissions: PermissionRuleset | NotGiven | None = NOT_GIVEN,
2532
+ extra_headers: Headers | None = None,
2533
+ extra_query: Query | None = None,
2534
+ extra_body: Body | None = None,
2535
+ timeout: Timeout | NotGiven = NOT_GIVEN,
2536
+ ) -> SessionInfo:
2537
+ """Create session.
2538
+
2539
+ Create a session at the requested location. A parentID creates a linked child session at its parent's location.
2540
+
2541
+ Raises:
2542
+ InvalidRequestError
2543
+ UnauthorizedError
2544
+ SessionNotFoundError
2545
+
2546
+ ``POST /api/session``
2547
+ """
2548
+ return cast(
2549
+ "SessionInfo",
2550
+ await self._client.request(
2551
+ RequestOptions(
2552
+ method="POST",
2553
+ path="/api/session",
2554
+ body={
2555
+ "id": id,
2556
+ "parentID": parent_id,
2557
+ "title": title,
2558
+ "agent": agent,
2559
+ "model": model,
2560
+ "location": self._location(location),
2561
+ "metadata": metadata,
2562
+ "permissions": permissions,
2563
+ },
2564
+ extra_headers=extra_headers,
2565
+ extra_query=extra_query,
2566
+ extra_body=extra_body,
2567
+ timeout=timeout,
2568
+ ),
2569
+ response_type=SessionInfo,
2570
+ unwrap=True,
2571
+ ),
2572
+ )
2573
+
2574
+ async def import_(
2575
+ self,
2576
+ *,
2577
+ info: SessionInfo,
2578
+ messages: Sequence[Any],
2579
+ location: LocationPublicRef | NotGiven | None = NOT_GIVEN,
2580
+ extra_headers: Headers | None = None,
2581
+ extra_query: Query | None = None,
2582
+ extra_body: Body | None = None,
2583
+ timeout: Timeout | NotGiven = NOT_GIVEN,
2584
+ ) -> SessionInfo:
2585
+ """Import session.
2586
+
2587
+ Import a projected session transcript at the requested location. Accepts transcripts exported by earlier releases. If parentID is supplied, the parent session must already exist; import parents before children.
2588
+
2589
+ This endpoint is experimental in OpenCode and may change without notice.
2590
+
2591
+ Raises:
2592
+ InvalidRequestError
2593
+ UnauthorizedError
2594
+ SessionNotFoundError
2595
+ ConflictError
2596
+
2597
+ ``POST /api/experimental/session/import``
2598
+ """
2599
+ return cast(
2600
+ "SessionInfo",
2601
+ await self._client.request(
2602
+ RequestOptions(
2603
+ method="POST",
2604
+ path="/api/experimental/session/import",
2605
+ body={"info": info, "messages": messages, "location": self._location(location)},
2606
+ extra_headers=extra_headers,
2607
+ extra_query=extra_query,
2608
+ extra_body=extra_body,
2609
+ timeout=timeout,
2610
+ ),
2611
+ response_type=SessionInfo,
2612
+ unwrap=True,
2613
+ ),
2614
+ )
2615
+
2616
+ async def export(
2617
+ self,
2618
+ session_id: SessionID,
2619
+ *,
2620
+ sanitize: bool | NotGiven | None = NOT_GIVEN,
2621
+ extra_headers: Headers | None = None,
2622
+ extra_query: Query | None = None,
2623
+ extra_body: Body | None = None,
2624
+ timeout: Timeout | NotGiven = NOT_GIVEN,
2625
+ ) -> SessionTransferData:
2626
+ """Export session.
2627
+
2628
+ Export a complete projected session transcript.
2629
+
2630
+ This endpoint is experimental in OpenCode and may change without notice.
2631
+
2632
+ Raises:
2633
+ InvalidRequestError
2634
+ UnauthorizedError
2635
+ SessionNotFoundError
2636
+ UnknownError
2637
+
2638
+ ``GET /api/experimental/session/:sessionID/export``
2639
+ """
2640
+ return cast(
2641
+ "SessionTransferData",
2642
+ await self._client.request(
2643
+ RequestOptions(
2644
+ method="GET",
2645
+ path=f"/api/experimental/session/{encode_path_segment(session_id)}/export",
2646
+ query={"sanitize": sanitize},
2647
+ extra_headers=extra_headers,
2648
+ extra_query=extra_query,
2649
+ extra_body=extra_body,
2650
+ timeout=timeout,
2651
+ ),
2652
+ response_type=SessionTransferData,
2653
+ unwrap=True,
2654
+ ),
2655
+ )
2656
+
2657
+ async def active(
2658
+ self,
2659
+ *,
2660
+ extra_headers: Headers | None = None,
2661
+ extra_query: Query | None = None,
2662
+ extra_body: Body | None = None,
2663
+ timeout: Timeout | NotGiven = NOT_GIVEN,
2664
+ ) -> builtins.dict[str, Any]:
2665
+ """List active sessions.
2666
+
2667
+ Retrieve foreground Session drains currently owned by this OpenCode process. Sessions absent from the result are inactive.
2668
+
2669
+ Raises:
2670
+ InvalidRequestError
2671
+ UnauthorizedError
2672
+
2673
+ ``GET /api/session/active``
2674
+ """
2675
+ return cast(
2676
+ "builtins.dict[str, Any]",
2677
+ await self._client.request(
2678
+ RequestOptions(
2679
+ method="GET",
2680
+ path="/api/session/active",
2681
+ extra_headers=extra_headers,
2682
+ extra_query=extra_query,
2683
+ extra_body=extra_body,
2684
+ timeout=timeout,
2685
+ ),
2686
+ response_type=builtins.dict[str, Any],
2687
+ unwrap=True,
2688
+ ),
2689
+ )
2690
+
2691
+ async def get(
2692
+ self,
2693
+ session_id: SessionID,
2694
+ *,
2695
+ extra_headers: Headers | None = None,
2696
+ extra_query: Query | None = None,
2697
+ extra_body: Body | None = None,
2698
+ timeout: Timeout | NotGiven = NOT_GIVEN,
2699
+ ) -> SessionInfo:
2700
+ """Get session.
2701
+
2702
+ Retrieve a session by ID.
2703
+
2704
+ Raises:
2705
+ InvalidRequestError
2706
+ UnauthorizedError
2707
+ SessionNotFoundError
2708
+
2709
+ ``GET /api/session/:sessionID``
2710
+ """
2711
+ return cast(
2712
+ "SessionInfo",
2713
+ await self._client.request(
2714
+ RequestOptions(
2715
+ method="GET",
2716
+ path=f"/api/session/{encode_path_segment(session_id)}",
2717
+ extra_headers=extra_headers,
2718
+ extra_query=extra_query,
2719
+ extra_body=extra_body,
2720
+ timeout=timeout,
2721
+ ),
2722
+ response_type=SessionInfo,
2723
+ unwrap=True,
2724
+ ),
2725
+ )
2726
+
2727
+ async def remove(
2728
+ self,
2729
+ session_id: SessionID,
2730
+ *,
2731
+ extra_headers: Headers | None = None,
2732
+ extra_query: Query | None = None,
2733
+ extra_body: Body | None = None,
2734
+ timeout: Timeout | NotGiven = NOT_GIVEN,
2735
+ ) -> None:
2736
+ """Delete session.
2737
+
2738
+ Delete a session and its child sessions.
2739
+
2740
+ Raises:
2741
+ InvalidRequestError
2742
+ UnauthorizedError
2743
+ SessionNotFoundError
2744
+
2745
+ ``DELETE /api/session/:sessionID``
2746
+ """
2747
+ await self._client.request(
2748
+ RequestOptions(
2749
+ method="DELETE",
2750
+ path=f"/api/session/{encode_path_segment(session_id)}",
2751
+ extra_headers=extra_headers,
2752
+ extra_query=extra_query,
2753
+ extra_body=extra_body,
2754
+ timeout=timeout,
2755
+ ),
2756
+ kind="void",
2757
+ )
2758
+
2759
+ async def fork(
2760
+ self,
2761
+ session_id: SessionID,
2762
+ *,
2763
+ before: SessionMessageID | NotGiven | None = NOT_GIVEN,
2764
+ extra_headers: Headers | None = None,
2765
+ extra_query: Query | None = None,
2766
+ extra_body: Body | None = None,
2767
+ timeout: Timeout | NotGiven = NOT_GIVEN,
2768
+ ) -> SessionInfo:
2769
+ """Fork session.
2770
+
2771
+ Create a child session by copying projected history before a message. Omit before to copy the full history.
2772
+
2773
+ Raises:
2774
+ InvalidRequestError
2775
+ UnauthorizedError
2776
+ SessionNotFoundError
2777
+ MessageNotFoundError
2778
+ LocationNotFoundError
2779
+
2780
+ ``POST /api/session/:sessionID/fork``
2781
+ """
2782
+ return cast(
2783
+ "SessionInfo",
2784
+ await self._client.request(
2785
+ RequestOptions(
2786
+ method="POST",
2787
+ path=f"/api/session/{encode_path_segment(session_id)}/fork",
2788
+ body={"before": before},
2789
+ extra_headers=extra_headers,
2790
+ extra_query=extra_query,
2791
+ extra_body=extra_body,
2792
+ timeout=timeout,
2793
+ ),
2794
+ response_type=SessionInfo,
2795
+ unwrap=True,
2796
+ ),
2797
+ )
2798
+
2799
+ async def switch_agent(
2800
+ self,
2801
+ session_id: SessionID,
2802
+ *,
2803
+ agent: AgentID,
2804
+ extra_headers: Headers | None = None,
2805
+ extra_query: Query | None = None,
2806
+ extra_body: Body | None = None,
2807
+ timeout: Timeout | NotGiven = NOT_GIVEN,
2808
+ ) -> None:
2809
+ """Switch session agent.
2810
+
2811
+ Switch the agent used by subsequent provider turns.
2812
+
2813
+ Raises:
2814
+ InvalidRequestError
2815
+ UnauthorizedError
2816
+ SessionNotFoundError
2817
+ LocationNotFoundError
2818
+
2819
+ ``POST /api/session/:sessionID/agent``
2820
+ """
2821
+ await self._client.request(
2822
+ RequestOptions(
2823
+ method="POST",
2824
+ path=f"/api/session/{encode_path_segment(session_id)}/agent",
2825
+ body={"agent": agent},
2826
+ extra_headers=extra_headers,
2827
+ extra_query=extra_query,
2828
+ extra_body=extra_body,
2829
+ timeout=timeout,
2830
+ ),
2831
+ kind="void",
2832
+ )
2833
+
2834
+ async def switch_model(
2835
+ self,
2836
+ session_id: SessionID,
2837
+ *,
2838
+ model: ModelRef,
2839
+ extra_headers: Headers | None = None,
2840
+ extra_query: Query | None = None,
2841
+ extra_body: Body | None = None,
2842
+ timeout: Timeout | NotGiven = NOT_GIVEN,
2843
+ ) -> None:
2844
+ """Switch session model.
2845
+
2846
+ Switch the model used by subsequent provider turns.
2847
+
2848
+ Raises:
2849
+ InvalidRequestError
2850
+ UnauthorizedError
2851
+ SessionNotFoundError
2852
+ LocationNotFoundError
2853
+
2854
+ ``POST /api/session/:sessionID/model``
2855
+ """
2856
+ await self._client.request(
2857
+ RequestOptions(
2858
+ method="POST",
2859
+ path=f"/api/session/{encode_path_segment(session_id)}/model",
2860
+ body={"model": model},
2861
+ extra_headers=extra_headers,
2862
+ extra_query=extra_query,
2863
+ extra_body=extra_body,
2864
+ timeout=timeout,
2865
+ ),
2866
+ kind="void",
2867
+ )
2868
+
2869
+ async def update(
2870
+ self,
2871
+ session_id: SessionID,
2872
+ *,
2873
+ title: str | NotGiven | None = NOT_GIVEN,
2874
+ metadata: SessionMetadata | NotGiven | None = NOT_GIVEN,
2875
+ permissions: PermissionRuleset | NotGiven | None = NOT_GIVEN,
2876
+ archived: bool | NotGiven | None = NOT_GIVEN,
2877
+ extra_headers: Headers | None = None,
2878
+ extra_query: Query | None = None,
2879
+ extra_body: Body | None = None,
2880
+ timeout: Timeout | NotGiven = NOT_GIVEN,
2881
+ ) -> None:
2882
+ """Update session.
2883
+
2884
+ Update mutable session properties.
2885
+
2886
+ Args:
2887
+ archived: Archive the session with true or restore it with false. Repeating the current state is a no-op.
2888
+
2889
+ Raises:
2890
+ InvalidRequestError
2891
+ UnauthorizedError
2892
+ SessionNotFoundError
2893
+ LocationNotFoundError
2894
+
2895
+ ``PATCH /api/session/:sessionID``
2896
+ """
2897
+ await self._client.request(
2898
+ RequestOptions(
2899
+ method="PATCH",
2900
+ path=f"/api/session/{encode_path_segment(session_id)}",
2901
+ body={"title": title, "metadata": metadata, "permissions": permissions, "archived": archived},
2902
+ extra_headers=extra_headers,
2903
+ extra_query=extra_query,
2904
+ extra_body=extra_body,
2905
+ timeout=timeout,
2906
+ ),
2907
+ kind="void",
2908
+ )
2909
+
2910
+ async def move(
2911
+ self,
2912
+ session_id: SessionID,
2913
+ *,
2914
+ directory: AbsolutePath,
2915
+ delivery: SessionInboxDelivery | NotGiven | None = NOT_GIVEN,
2916
+ extra_headers: Headers | None = None,
2917
+ extra_query: Query | None = None,
2918
+ extra_body: Body | None = None,
2919
+ timeout: Timeout | NotGiven = NOT_GIVEN,
2920
+ ) -> None:
2921
+ """Move session.
2922
+
2923
+ Move a session to another project directory at the requested delivery boundary.
2924
+
2925
+ Raises:
2926
+ InvalidRequestError
2927
+ UnauthorizedError
2928
+ SessionNotFoundError
2929
+
2930
+ ``POST /api/session/:sessionID/move``
2931
+ """
2932
+ await self._client.request(
2933
+ RequestOptions(
2934
+ method="POST",
2935
+ path=f"/api/session/{encode_path_segment(session_id)}/move",
2936
+ body={"directory": directory, "delivery": delivery},
2937
+ extra_headers=extra_headers,
2938
+ extra_query=extra_query,
2939
+ extra_body=extra_body,
2940
+ timeout=timeout,
2941
+ ),
2942
+ kind="void",
2943
+ )
2944
+
2945
+ async def prompt(
2946
+ self,
2947
+ session_id: SessionID,
2948
+ *,
2949
+ text: str,
2950
+ id: SessionMessageID | NotGiven | None = NOT_GIVEN,
2951
+ files: Sequence[PromptInputFileAttachment] | NotGiven = NOT_GIVEN,
2952
+ agents: Sequence[PromptAgentAttachment] | NotGiven = NOT_GIVEN,
2953
+ skills: Sequence[PromptInputSkillAttachment] | NotGiven = NOT_GIVEN,
2954
+ metadata: Mapping[str, Any] | NotGiven = NOT_GIVEN,
2955
+ delivery: SessionInboxDelivery | NotGiven | None = NOT_GIVEN,
2956
+ resume: bool | NotGiven | None = NOT_GIVEN,
2957
+ extra_headers: Headers | None = None,
2958
+ extra_query: Query | None = None,
2959
+ extra_body: Body | None = None,
2960
+ timeout: Timeout | NotGiven = NOT_GIVEN,
2961
+ ) -> SessionInboxUser:
2962
+ """Send message.
2963
+
2964
+ Durably admit one session input and schedule agent-loop execution unless resume is false.
2965
+
2966
+ Raises:
2967
+ InvalidRequestError
2968
+ UnauthorizedError
2969
+ SessionNotFoundError
2970
+ LocationNotFoundError
2971
+ ConflictError
2972
+
2973
+ ``POST /api/session/:sessionID/prompt``
2974
+ """
2975
+ return cast(
2976
+ "SessionInboxUser",
2977
+ await self._client.request(
2978
+ RequestOptions(
2979
+ method="POST",
2980
+ path=f"/api/session/{encode_path_segment(session_id)}/prompt",
2981
+ body={
2982
+ "id": id,
2983
+ "text": text,
2984
+ "files": files,
2985
+ "agents": agents,
2986
+ "skills": skills,
2987
+ "metadata": metadata,
2988
+ "delivery": delivery,
2989
+ "resume": resume,
2990
+ },
2991
+ extra_headers=extra_headers,
2992
+ extra_query=extra_query,
2993
+ extra_body=extra_body,
2994
+ timeout=timeout,
2995
+ ),
2996
+ response_type=SessionInboxUser,
2997
+ unwrap=True,
2998
+ ),
2999
+ )
3000
+
3001
+ async def command(
3002
+ self,
3003
+ session_id: SessionID,
3004
+ *,
3005
+ name: str,
3006
+ text: str,
3007
+ files: Sequence[PromptInputFileAttachment] | NotGiven = NOT_GIVEN,
3008
+ agents: Sequence[PromptAgentAttachment] | NotGiven = NOT_GIVEN,
3009
+ skills: Sequence[PromptInputSkillAttachment] | NotGiven = NOT_GIVEN,
3010
+ delivery: SessionInboxDelivery | NotGiven | None = NOT_GIVEN,
3011
+ extra_headers: Headers | None = None,
3012
+ extra_query: Query | None = None,
3013
+ extra_body: Body | None = None,
3014
+ timeout: Timeout | NotGiven = NOT_GIVEN,
3015
+ ) -> None:
3016
+ """Run command.
3017
+
3018
+ Execute a slash command callback immediately.
3019
+
3020
+ Raises:
3021
+ InvalidRequestError
3022
+ UnauthorizedError
3023
+ SessionNotFoundError
3024
+ CommandNotFoundError
3025
+ LocationNotFoundError
3026
+ CommandExecutionError
3027
+
3028
+ ``POST /api/session/:sessionID/command``
3029
+ """
3030
+ await self._client.request(
3031
+ RequestOptions(
3032
+ method="POST",
3033
+ path=f"/api/session/{encode_path_segment(session_id)}/command",
3034
+ body={
3035
+ "name": name,
3036
+ "text": text,
3037
+ "files": files,
3038
+ "agents": agents,
3039
+ "skills": skills,
3040
+ "delivery": delivery,
3041
+ },
3042
+ extra_headers=extra_headers,
3043
+ extra_query=extra_query,
3044
+ extra_body=extra_body,
3045
+ timeout=timeout,
3046
+ ),
3047
+ kind="void",
3048
+ )
3049
+
3050
+ async def skill(
3051
+ self,
3052
+ session_id: SessionID,
3053
+ *,
3054
+ id: SkillID,
3055
+ resume: bool | NotGiven | None = NOT_GIVEN,
3056
+ extra_headers: Headers | None = None,
3057
+ extra_query: Query | None = None,
3058
+ extra_body: Body | None = None,
3059
+ timeout: Timeout | NotGiven = NOT_GIVEN,
3060
+ ) -> None:
3061
+ """Activate skill.
3062
+
3063
+ Activate a skill for a session by appending a skill message and resuming execution.
3064
+
3065
+ This endpoint is experimental in OpenCode and may change without notice.
3066
+
3067
+ Raises:
3068
+ InvalidRequestError
3069
+ UnauthorizedError
3070
+ SessionNotFoundError
3071
+ SkillNotFoundError
3072
+ LocationNotFoundError
3073
+
3074
+ ``POST /api/experimental/session/:sessionID/skill``
3075
+ """
3076
+ await self._client.request(
3077
+ RequestOptions(
3078
+ method="POST",
3079
+ path=f"/api/experimental/session/{encode_path_segment(session_id)}/skill",
3080
+ body={"id": id, "resume": resume},
3081
+ extra_headers=extra_headers,
3082
+ extra_query=extra_query,
3083
+ extra_body=extra_body,
3084
+ timeout=timeout,
3085
+ ),
3086
+ kind="void",
3087
+ )
3088
+
3089
+ async def synthetic(
3090
+ self,
3091
+ session_id: SessionID,
3092
+ *,
3093
+ text: str,
3094
+ id: SessionMessageID | NotGiven | None = NOT_GIVEN,
3095
+ description: str | NotGiven | None = NOT_GIVEN,
3096
+ metadata: Mapping[str, Any] | NotGiven = NOT_GIVEN,
3097
+ delivery: SessionInboxDelivery | NotGiven | None = NOT_GIVEN,
3098
+ resume: bool | NotGiven | None = NOT_GIVEN,
3099
+ extra_headers: Headers | None = None,
3100
+ extra_query: Query | None = None,
3101
+ extra_body: Body | None = None,
3102
+ timeout: Timeout | NotGiven = NOT_GIVEN,
3103
+ ) -> SessionInboxSynthetic:
3104
+ """Add synthetic message.
3105
+
3106
+ Durably admit synthetic session input and schedule execution unless resume is false.
3107
+
3108
+ Raises:
3109
+ InvalidRequestError
3110
+ UnauthorizedError
3111
+ SessionNotFoundError
3112
+ LocationNotFoundError
3113
+ ConflictError
3114
+
3115
+ ``POST /api/session/:sessionID/synthetic``
3116
+ """
3117
+ return cast(
3118
+ "SessionInboxSynthetic",
3119
+ await self._client.request(
3120
+ RequestOptions(
3121
+ method="POST",
3122
+ path=f"/api/session/{encode_path_segment(session_id)}/synthetic",
3123
+ body={
3124
+ "id": id,
3125
+ "text": text,
3126
+ "description": description,
3127
+ "metadata": metadata,
3128
+ "delivery": delivery,
3129
+ "resume": resume,
3130
+ },
3131
+ extra_headers=extra_headers,
3132
+ extra_query=extra_query,
3133
+ extra_body=extra_body,
3134
+ timeout=timeout,
3135
+ ),
3136
+ response_type=SessionInboxSynthetic,
3137
+ unwrap=True,
3138
+ ),
3139
+ )
3140
+
3141
+ async def shell(
3142
+ self,
3143
+ session_id: SessionID,
3144
+ *,
3145
+ command: str,
3146
+ id: SessionMessageID | NotGiven | None = NOT_GIVEN,
3147
+ extra_headers: Headers | None = None,
3148
+ extra_query: Query | None = None,
3149
+ extra_body: Body | None = None,
3150
+ timeout: Timeout | NotGiven = NOT_GIVEN,
3151
+ ) -> None:
3152
+ """Run shell command.
3153
+
3154
+ Execute one shell command in the session's working directory. Emits a shell.started event before execution and a shell.ended event with the merged output after.
3155
+
3156
+ Raises:
3157
+ InvalidRequestError
3158
+ UnauthorizedError
3159
+ SessionNotFoundError
3160
+ LocationNotFoundError
3161
+
3162
+ ``POST /api/session/:sessionID/shell``
3163
+ """
3164
+ await self._client.request(
3165
+ RequestOptions(
3166
+ method="POST",
3167
+ path=f"/api/session/{encode_path_segment(session_id)}/shell",
3168
+ body={"id": id, "command": command},
3169
+ extra_headers=extra_headers,
3170
+ extra_query=extra_query,
3171
+ extra_body=extra_body,
3172
+ timeout=timeout,
3173
+ ),
3174
+ kind="void",
3175
+ )
3176
+
3177
+ async def compact(
3178
+ self,
3179
+ session_id: SessionID,
3180
+ *,
3181
+ id: SessionMessageID | NotGiven | None = NOT_GIVEN,
3182
+ delivery: SessionInboxDelivery | NotGiven | None = NOT_GIVEN,
3183
+ extra_headers: Headers | None = None,
3184
+ extra_query: Query | None = None,
3185
+ extra_body: Body | None = None,
3186
+ timeout: Timeout | NotGiven = NOT_GIVEN,
3187
+ ) -> SessionInboxCompaction:
3188
+ """Compact session.
3189
+
3190
+ Durably admit a session compaction request. Steers by default: it runs at the next step boundary instead of waiting behind queued prompts.
3191
+
3192
+ Raises:
3193
+ InvalidRequestError
3194
+ UnauthorizedError
3195
+ SessionNotFoundError
3196
+ LocationNotFoundError
3197
+ ConflictError
3198
+
3199
+ ``POST /api/session/:sessionID/compact``
3200
+ """
3201
+ return cast(
3202
+ "SessionInboxCompaction",
3203
+ await self._client.request(
3204
+ RequestOptions(
3205
+ method="POST",
3206
+ path=f"/api/session/{encode_path_segment(session_id)}/compact",
3207
+ body={"id": id, "delivery": delivery},
3208
+ extra_headers=extra_headers,
3209
+ extra_query=extra_query,
3210
+ extra_body=extra_body,
3211
+ timeout=timeout,
3212
+ ),
3213
+ response_type=SessionInboxCompaction,
3214
+ unwrap=True,
3215
+ ),
3216
+ )
3217
+
3218
+ async def wait(
3219
+ self,
3220
+ session_id: SessionID,
3221
+ *,
3222
+ extra_headers: Headers | None = None,
3223
+ extra_query: Query | None = None,
3224
+ extra_body: Body | None = None,
3225
+ timeout: Timeout | NotGiven = NOT_GIVEN,
3226
+ ) -> None:
3227
+ """Wait for session.
3228
+
3229
+ Wait for a session agent loop to become idle.
3230
+
3231
+ This endpoint is experimental in OpenCode and may change without notice.
3232
+
3233
+ Raises:
3234
+ InvalidRequestError
3235
+ UnauthorizedError
3236
+ SessionNotFoundError
3237
+ LocationNotFoundError
3238
+ ServiceUnavailableError
3239
+
3240
+ ``POST /api/experimental/session/:sessionID/wait``
3241
+ """
3242
+ await self._client.request(
3243
+ RequestOptions(
3244
+ method="POST",
3245
+ path=f"/api/experimental/session/{encode_path_segment(session_id)}/wait",
3246
+ extra_headers=extra_headers,
3247
+ extra_query=extra_query,
3248
+ extra_body=extra_body,
3249
+ timeout=timeout,
3250
+ ),
3251
+ kind="void",
3252
+ )
3253
+
3254
+ async def context(
3255
+ self,
3256
+ session_id: SessionID,
3257
+ *,
3258
+ extra_headers: Headers | None = None,
3259
+ extra_query: Query | None = None,
3260
+ extra_body: Body | None = None,
3261
+ timeout: Timeout | NotGiven = NOT_GIVEN,
3262
+ ) -> builtins.list[SessionMessageInfo]:
3263
+ """Get session context.
3264
+
3265
+ Retrieve the active context messages for a session (all messages after the last compaction).
3266
+
3267
+ Raises:
3268
+ InvalidRequestError
3269
+ UnauthorizedError
3270
+ SessionNotFoundError
3271
+ UnknownError
3272
+
3273
+ ``GET /api/session/:sessionID/context``
3274
+ """
3275
+ return cast(
3276
+ "builtins.list[SessionMessageInfo]",
3277
+ await self._client.request(
3278
+ RequestOptions(
3279
+ method="GET",
3280
+ path=f"/api/session/{encode_path_segment(session_id)}/context",
3281
+ extra_headers=extra_headers,
3282
+ extra_query=extra_query,
3283
+ extra_body=extra_body,
3284
+ timeout=timeout,
3285
+ ),
3286
+ response_type=builtins.list[SessionMessageInfo],
3287
+ unwrap=True,
3288
+ ),
3289
+ )
3290
+
3291
+ async def diff(
3292
+ self,
3293
+ session_id: SessionID,
3294
+ *,
3295
+ from_: SessionMessageID | NotGiven | None = NOT_GIVEN,
3296
+ to: SessionMessageID | NotGiven | None = NOT_GIVEN,
3297
+ context: int | NotGiven | None = NOT_GIVEN,
3298
+ extra_headers: Headers | None = None,
3299
+ extra_query: Query | None = None,
3300
+ extra_body: Body | None = None,
3301
+ timeout: Timeout | NotGiven = NOT_GIVEN,
3302
+ ) -> builtins.list[FileDiffInfo]:
3303
+ """Diff session turns.
3304
+
3305
+ Structured per-file diffs of the files a turn changed. A turn runs from the first prompt after the session was last idle until its next idle marker, so prompts steered in while it was busy belong to the same turn; `to` extends the range through a later turn. Compares the range's first recorded snapshot with its last; a step still running in the active session compares against the working copy. Ranges that span a location change are rejected. In sessions without any idle marker, a prompt's turn spans until the next user message.
3306
+
3307
+ Args:
3308
+ from_: User message whose turn to diff. Defaults to the turn of the newest user message.
3309
+ to: Later user message whose turn ends the range. Defaults to the turn of `from` alone.
3310
+ context: Unchanged lines around each hunk. Omit for full-file patches.
3311
+
3312
+ Raises:
3313
+ InvalidRequestError
3314
+ UnauthorizedError
3315
+ MessageNotFoundError
3316
+ SessionNotFoundError
3317
+ LocationNotFoundError
3318
+ UnknownError
3319
+
3320
+ ``GET /api/session/:sessionID/diff``
3321
+ """
3322
+ return cast(
3323
+ "builtins.list[FileDiffInfo]",
3324
+ await self._client.request(
3325
+ RequestOptions(
3326
+ method="GET",
3327
+ path=f"/api/session/{encode_path_segment(session_id)}/diff",
3328
+ query={"from": from_, "to": to, "context": context},
3329
+ extra_headers=extra_headers,
3330
+ extra_query=extra_query,
3331
+ extra_body=extra_body,
3332
+ timeout=timeout,
3333
+ ),
3334
+ response_type=builtins.list[FileDiffInfo],
3335
+ unwrap=True,
3336
+ ),
3337
+ )
3338
+
3339
+ async def generate(
3340
+ self,
3341
+ session_id: SessionID,
3342
+ *,
3343
+ prompt: str,
3344
+ extra_headers: Headers | None = None,
3345
+ extra_query: Query | None = None,
3346
+ extra_body: Body | None = None,
3347
+ timeout: Timeout | NotGiven = NOT_GIVEN,
3348
+ ) -> SessionGenerateResponseData:
3349
+ """Generate text from session context.
3350
+
3351
+ Generate transient text from the current session context without mutating session history.
3352
+
3353
+ Raises:
3354
+ InvalidRequestError
3355
+ UnauthorizedError
3356
+ SessionNotFoundError
3357
+ LocationNotFoundError
3358
+ ServiceUnavailableError
3359
+
3360
+ ``POST /api/session/:sessionID/generate``
3361
+ """
3362
+ return cast(
3363
+ "SessionGenerateResponseData",
3364
+ await self._client.request(
3365
+ RequestOptions(
3366
+ method="POST",
3367
+ path=f"/api/session/{encode_path_segment(session_id)}/generate",
3368
+ body={"prompt": prompt},
3369
+ extra_headers=extra_headers,
3370
+ extra_query=extra_query,
3371
+ extra_body=extra_body,
3372
+ timeout=timeout,
3373
+ ),
3374
+ response_type=SessionGenerateResponseData,
3375
+ unwrap=True,
3376
+ ),
3377
+ )
3378
+
3379
+ async def log(
3380
+ self,
3381
+ session_id: SessionID,
3382
+ *,
3383
+ after: EventSeq | NotGiven | None = NOT_GIVEN,
3384
+ follow: bool | NotGiven | None = NOT_GIVEN,
3385
+ extra_headers: Headers | None = None,
3386
+ extra_query: Query | None = None,
3387
+ extra_body: Body | None = None,
3388
+ timeout: Timeout | NotGiven = NOT_GIVEN,
3389
+ ) -> AsyncStream[SessionLogItem]:
3390
+ """Read the session log.
3391
+
3392
+ Experimental durable session event log. Reads events after an exclusive aggregate sequence and continues with live events when follow=true.
3393
+
3394
+ This endpoint is experimental in OpenCode and may change without notice.
3395
+
3396
+ Raises:
3397
+ InvalidRequestError
3398
+ UnauthorizedError
3399
+ SessionNotFoundError
3400
+
3401
+ ``GET /api/experimental/session/:sessionID/log``
3402
+ """
3403
+ return await self._client.stream(
3404
+ RequestOptions(
3405
+ method="GET",
3406
+ path=f"/api/experimental/session/{encode_path_segment(session_id)}/log",
3407
+ query={"after": after, "follow": follow},
3408
+ extra_headers=extra_headers,
3409
+ extra_query=extra_query,
3410
+ extra_body=extra_body,
3411
+ timeout=timeout,
3412
+ ),
3413
+ item_type=SessionLogItem,
3414
+ )
3415
+
3416
+ async def interrupt(
3417
+ self,
3418
+ session_id: SessionID,
3419
+ *,
3420
+ resume: bool | NotGiven | None = NOT_GIVEN,
3421
+ extra_headers: Headers | None = None,
3422
+ extra_query: Query | None = None,
3423
+ extra_body: Body | None = None,
3424
+ timeout: Timeout | NotGiven = NOT_GIVEN,
3425
+ ) -> SessionInterruptResponse:
3426
+ """Interrupt session execution.
3427
+
3428
+ Interrupt active execution owned by this OpenCode process. Returns interrupted=true when an active execution was interrupted and false for the idle no-op. When resume=true, execution resumes pending steering input and next-in-line control items (manual compaction, moves) while queued prompts remain parked.
3429
+
3430
+ Raises:
3431
+ InvalidRequestError
3432
+ UnauthorizedError
3433
+ SessionNotFoundError
3434
+ LocationNotFoundError
3435
+
3436
+ ``POST /api/session/:sessionID/interrupt``
3437
+ """
3438
+ return cast(
3439
+ "SessionInterruptResponse",
3440
+ await self._client.request(
3441
+ RequestOptions(
3442
+ method="POST",
3443
+ path=f"/api/session/{encode_path_segment(session_id)}/interrupt",
3444
+ query={"resume": resume},
3445
+ extra_headers=extra_headers,
3446
+ extra_query=extra_query,
3447
+ extra_body=extra_body,
3448
+ timeout=timeout,
3449
+ ),
3450
+ response_type=SessionInterruptResponse,
3451
+ ),
3452
+ )
3453
+
3454
+ async def background(
3455
+ self,
3456
+ session_id: SessionID,
3457
+ *,
3458
+ extra_headers: Headers | None = None,
3459
+ extra_query: Query | None = None,
3460
+ extra_body: Body | None = None,
3461
+ timeout: Timeout | NotGiven = NOT_GIVEN,
3462
+ ) -> None:
3463
+ """Background blocking session tools.
3464
+
3465
+ Move active foreground backgroundable tools for this session into background observation. Idle requests are a no-op.
3466
+
3467
+ Raises:
3468
+ InvalidRequestError
3469
+ UnauthorizedError
3470
+ SessionNotFoundError
3471
+ LocationNotFoundError
3472
+
3473
+ ``POST /api/session/:sessionID/background``
3474
+ """
3475
+ await self._client.request(
3476
+ RequestOptions(
3477
+ method="POST",
3478
+ path=f"/api/session/{encode_path_segment(session_id)}/background",
3479
+ extra_headers=extra_headers,
3480
+ extra_query=extra_query,
3481
+ extra_body=extra_body,
3482
+ timeout=timeout,
3483
+ ),
3484
+ kind="void",
3485
+ )
3486
+
3487
+ async def environment(
3488
+ self,
3489
+ session_id: SessionID,
3490
+ *,
3491
+ variables: Mapping[str, str],
3492
+ extra_headers: Headers | None = None,
3493
+ extra_query: Query | None = None,
3494
+ extra_body: Body | None = None,
3495
+ timeout: Timeout | NotGiven = NOT_GIVEN,
3496
+ ) -> None:
3497
+ """Set session environment.
3498
+
3499
+ Replace the process environment used by local shell commands for this session.
3500
+
3501
+ Raises:
3502
+ InvalidRequestError
3503
+ UnauthorizedError
3504
+ SessionNotFoundError
3505
+
3506
+ ``PUT /api/session/:sessionID/environment``
3507
+ """
3508
+ await self._client.request(
3509
+ RequestOptions(
3510
+ method="PUT",
3511
+ path=f"/api/session/{encode_path_segment(session_id)}/environment",
3512
+ body={"variables": variables},
3513
+ extra_headers=extra_headers,
3514
+ extra_query=extra_query,
3515
+ extra_body=extra_body,
3516
+ timeout=timeout,
3517
+ ),
3518
+ kind="void",
3519
+ )
3520
+
3521
+ async def view(
3522
+ self,
3523
+ session_id: SessionID,
3524
+ *,
3525
+ idle: float,
3526
+ extra_headers: Headers | None = None,
3527
+ extra_query: Query | None = None,
3528
+ extra_body: Body | None = None,
3529
+ timeout: Timeout | NotGiven = NOT_GIVEN,
3530
+ ) -> None:
3531
+ """View session.
3532
+
3533
+ Mark the idle transition observed by the viewer as viewed.
3534
+
3535
+ Raises:
3536
+ InvalidRequestError
3537
+ UnauthorizedError
3538
+ SessionNotFoundError
3539
+
3540
+ ``POST /api/session/:sessionID/view``
3541
+ """
3542
+ await self._client.request(
3543
+ RequestOptions(
3544
+ method="POST",
3545
+ path=f"/api/session/{encode_path_segment(session_id)}/view",
3546
+ body={"idle": idle},
3547
+ extra_headers=extra_headers,
3548
+ extra_query=extra_query,
3549
+ extra_body=extra_body,
3550
+ timeout=timeout,
3551
+ ),
3552
+ kind="void",
3553
+ )