codex-ipc 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.
- codex_app_server/__init__.py +112 -0
- codex_app_server/_inputs.py +63 -0
- codex_app_server/_message_router.py +158 -0
- codex_app_server/_run.py +112 -0
- codex_app_server/_version.py +37 -0
- codex_app_server/api.py +764 -0
- codex_app_server/async_client.py +214 -0
- codex_app_server/client.py +582 -0
- codex_app_server/errors.py +125 -0
- codex_app_server/generated/__init__.py +1 -0
- codex_app_server/generated/notification_registry.py +172 -0
- codex_app_server/generated/v2_all.py +8715 -0
- codex_app_server/models.py +99 -0
- codex_app_server/py.typed +0 -0
- codex_app_server/retry.py +41 -0
- codex_ipc/__init__.py +28 -0
- codex_ipc/codex/__init__.py +0 -0
- codex_ipc/codex/api.py +285 -0
- codex_ipc/codex/async_client.py +77 -0
- codex_ipc/codex/client.py +245 -0
- codex_ipc/codex/generated/__init__.py +0 -0
- codex_ipc/codex/generated/v2_all.py +83 -0
- codex_ipc/config.py +28 -0
- codex_ipc/session.py +509 -0
- codex_ipc/user_input.py +174 -0
- codex_ipc-0.1.0.dist-info/METADATA +62 -0
- codex_ipc-0.1.0.dist-info/RECORD +37 -0
- codex_ipc-0.1.0.dist-info/WHEEL +4 -0
- ipc/__init__.py +22 -0
- ipc/client.py +459 -0
- ipc/constants.py +55 -0
- ipc/conversation_state.py +846 -0
- ipc/frame_protocol.py +84 -0
- ipc/immer.py +207 -0
- ipc/owner_follower.py +2651 -0
- ipc/py.typed +0 -0
- ipc/router.py +555 -0
codex_app_server/api.py
ADDED
|
@@ -0,0 +1,764 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
from typing import AsyncIterator, Iterator
|
|
6
|
+
|
|
7
|
+
from .async_client import AsyncAppServerClient
|
|
8
|
+
from .client import AppServerClient, AppServerConfig
|
|
9
|
+
from .generated.v2_all import (
|
|
10
|
+
ApprovalsReviewer,
|
|
11
|
+
AskForApproval,
|
|
12
|
+
ModelListResponse,
|
|
13
|
+
Personality,
|
|
14
|
+
ReasoningEffort,
|
|
15
|
+
ReasoningSummary,
|
|
16
|
+
SandboxMode,
|
|
17
|
+
SandboxPolicy,
|
|
18
|
+
ServiceTier,
|
|
19
|
+
SortDirection,
|
|
20
|
+
ThreadArchiveResponse,
|
|
21
|
+
ThreadCompactStartResponse,
|
|
22
|
+
ThreadForkParams,
|
|
23
|
+
ThreadListCwdFilter,
|
|
24
|
+
ThreadListParams,
|
|
25
|
+
ThreadListResponse,
|
|
26
|
+
ThreadReadResponse,
|
|
27
|
+
ThreadResumeParams,
|
|
28
|
+
ThreadSetNameResponse,
|
|
29
|
+
ThreadSortKey,
|
|
30
|
+
ThreadSourceKind,
|
|
31
|
+
ThreadStartSource,
|
|
32
|
+
ThreadStartParams,
|
|
33
|
+
Turn as AppServerTurn,
|
|
34
|
+
TurnCompletedNotification,
|
|
35
|
+
TurnInterruptResponse,
|
|
36
|
+
TurnStartParams,
|
|
37
|
+
TurnSteerResponse,
|
|
38
|
+
)
|
|
39
|
+
from .models import InitializeResponse, JsonObject, Notification, ServerInfo
|
|
40
|
+
from ._inputs import (
|
|
41
|
+
ImageInput as ImageInput,
|
|
42
|
+
Input,
|
|
43
|
+
InputItem as InputItem,
|
|
44
|
+
LocalImageInput as LocalImageInput,
|
|
45
|
+
MentionInput as MentionInput,
|
|
46
|
+
RunInput,
|
|
47
|
+
SkillInput as SkillInput,
|
|
48
|
+
TextInput as TextInput,
|
|
49
|
+
_normalize_run_input,
|
|
50
|
+
_to_wire_input,
|
|
51
|
+
)
|
|
52
|
+
from ._run import (
|
|
53
|
+
RunResult,
|
|
54
|
+
_collect_async_run_result,
|
|
55
|
+
_collect_run_result,
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _split_user_agent(user_agent: str) -> tuple[str | None, str | None]:
|
|
60
|
+
raw = user_agent.strip()
|
|
61
|
+
if not raw:
|
|
62
|
+
return None, None
|
|
63
|
+
if "/" in raw:
|
|
64
|
+
name, version = raw.split("/", 1)
|
|
65
|
+
return (name or None), (version or None)
|
|
66
|
+
parts = raw.split(maxsplit=1)
|
|
67
|
+
if len(parts) == 2:
|
|
68
|
+
return parts[0], parts[1]
|
|
69
|
+
return raw, None
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class Codex:
|
|
73
|
+
"""Minimal typed SDK surface for app-server v2."""
|
|
74
|
+
|
|
75
|
+
def __init__(self, config: AppServerConfig | None = None) -> None:
|
|
76
|
+
self._client = AppServerClient(config=config)
|
|
77
|
+
try:
|
|
78
|
+
self._client.start()
|
|
79
|
+
self._init = self._validate_initialize(self._client.initialize())
|
|
80
|
+
except Exception:
|
|
81
|
+
self._client.close()
|
|
82
|
+
raise
|
|
83
|
+
|
|
84
|
+
def __enter__(self) -> "Codex":
|
|
85
|
+
return self
|
|
86
|
+
|
|
87
|
+
def __exit__(self, _exc_type, _exc, _tb) -> None:
|
|
88
|
+
self.close()
|
|
89
|
+
|
|
90
|
+
@staticmethod
|
|
91
|
+
def _validate_initialize(payload: InitializeResponse) -> InitializeResponse:
|
|
92
|
+
user_agent = (payload.userAgent or "").strip()
|
|
93
|
+
server = payload.serverInfo
|
|
94
|
+
|
|
95
|
+
server_name: str | None = None
|
|
96
|
+
server_version: str | None = None
|
|
97
|
+
|
|
98
|
+
if server is not None:
|
|
99
|
+
server_name = (server.name or "").strip() or None
|
|
100
|
+
server_version = (server.version or "").strip() or None
|
|
101
|
+
|
|
102
|
+
if (server_name is None or server_version is None) and user_agent:
|
|
103
|
+
parsed_name, parsed_version = _split_user_agent(user_agent)
|
|
104
|
+
if server_name is None:
|
|
105
|
+
server_name = parsed_name
|
|
106
|
+
if server_version is None:
|
|
107
|
+
server_version = parsed_version
|
|
108
|
+
|
|
109
|
+
normalized_server_name = (server_name or "").strip()
|
|
110
|
+
normalized_server_version = (server_version or "").strip()
|
|
111
|
+
if (
|
|
112
|
+
not user_agent
|
|
113
|
+
or not normalized_server_name
|
|
114
|
+
or not normalized_server_version
|
|
115
|
+
):
|
|
116
|
+
raise RuntimeError(
|
|
117
|
+
"initialize response missing required metadata "
|
|
118
|
+
f"(user_agent={user_agent!r}, server_name={normalized_server_name!r}, server_version={normalized_server_version!r})"
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
if server is None:
|
|
122
|
+
payload.serverInfo = ServerInfo(
|
|
123
|
+
name=normalized_server_name,
|
|
124
|
+
version=normalized_server_version,
|
|
125
|
+
)
|
|
126
|
+
else:
|
|
127
|
+
server.name = normalized_server_name
|
|
128
|
+
server.version = normalized_server_version
|
|
129
|
+
|
|
130
|
+
return payload
|
|
131
|
+
|
|
132
|
+
@property
|
|
133
|
+
def metadata(self) -> InitializeResponse:
|
|
134
|
+
return self._init
|
|
135
|
+
|
|
136
|
+
def close(self) -> None:
|
|
137
|
+
self._client.close()
|
|
138
|
+
|
|
139
|
+
# BEGIN GENERATED: Codex.flat_methods
|
|
140
|
+
def thread_start(
|
|
141
|
+
self,
|
|
142
|
+
*,
|
|
143
|
+
approval_policy: AskForApproval | None = None,
|
|
144
|
+
approvals_reviewer: ApprovalsReviewer | None = None,
|
|
145
|
+
base_instructions: str | None = None,
|
|
146
|
+
config: JsonObject | None = None,
|
|
147
|
+
cwd: str | None = None,
|
|
148
|
+
developer_instructions: str | None = None,
|
|
149
|
+
ephemeral: bool | None = None,
|
|
150
|
+
model: str | None = None,
|
|
151
|
+
model_provider: str | None = None,
|
|
152
|
+
personality: Personality | None = None,
|
|
153
|
+
sandbox: SandboxMode | None = None,
|
|
154
|
+
service_name: str | None = None,
|
|
155
|
+
service_tier: ServiceTier | None = None,
|
|
156
|
+
session_start_source: ThreadStartSource | None = None,
|
|
157
|
+
) -> Thread:
|
|
158
|
+
params = ThreadStartParams(
|
|
159
|
+
approval_policy=approval_policy,
|
|
160
|
+
approvals_reviewer=approvals_reviewer,
|
|
161
|
+
base_instructions=base_instructions,
|
|
162
|
+
config=config,
|
|
163
|
+
cwd=cwd,
|
|
164
|
+
developer_instructions=developer_instructions,
|
|
165
|
+
ephemeral=ephemeral,
|
|
166
|
+
model=model,
|
|
167
|
+
model_provider=model_provider,
|
|
168
|
+
personality=personality,
|
|
169
|
+
sandbox=sandbox,
|
|
170
|
+
service_name=service_name,
|
|
171
|
+
service_tier=service_tier,
|
|
172
|
+
session_start_source=session_start_source,
|
|
173
|
+
)
|
|
174
|
+
started = self._client.thread_start(params)
|
|
175
|
+
return Thread(self._client, started.thread.id)
|
|
176
|
+
|
|
177
|
+
def thread_list(
|
|
178
|
+
self,
|
|
179
|
+
*,
|
|
180
|
+
archived: bool | None = None,
|
|
181
|
+
cursor: str | None = None,
|
|
182
|
+
cwd: ThreadListCwdFilter | None = None,
|
|
183
|
+
limit: int | None = None,
|
|
184
|
+
model_providers: list[str] | None = None,
|
|
185
|
+
search_term: str | None = None,
|
|
186
|
+
sort_direction: SortDirection | None = None,
|
|
187
|
+
sort_key: ThreadSortKey | None = None,
|
|
188
|
+
source_kinds: list[ThreadSourceKind] | None = None,
|
|
189
|
+
use_state_db_only: bool | None = None,
|
|
190
|
+
) -> ThreadListResponse:
|
|
191
|
+
params = ThreadListParams(
|
|
192
|
+
archived=archived,
|
|
193
|
+
cursor=cursor,
|
|
194
|
+
cwd=cwd,
|
|
195
|
+
limit=limit,
|
|
196
|
+
model_providers=model_providers,
|
|
197
|
+
search_term=search_term,
|
|
198
|
+
sort_direction=sort_direction,
|
|
199
|
+
sort_key=sort_key,
|
|
200
|
+
source_kinds=source_kinds,
|
|
201
|
+
use_state_db_only=use_state_db_only,
|
|
202
|
+
)
|
|
203
|
+
return self._client.thread_list(params)
|
|
204
|
+
|
|
205
|
+
def thread_resume(
|
|
206
|
+
self,
|
|
207
|
+
thread_id: str,
|
|
208
|
+
*,
|
|
209
|
+
approval_policy: AskForApproval | None = None,
|
|
210
|
+
approvals_reviewer: ApprovalsReviewer | None = None,
|
|
211
|
+
base_instructions: str | None = None,
|
|
212
|
+
config: JsonObject | None = None,
|
|
213
|
+
cwd: str | None = None,
|
|
214
|
+
developer_instructions: str | None = None,
|
|
215
|
+
model: str | None = None,
|
|
216
|
+
model_provider: str | None = None,
|
|
217
|
+
personality: Personality | None = None,
|
|
218
|
+
sandbox: SandboxMode | None = None,
|
|
219
|
+
service_tier: ServiceTier | None = None,
|
|
220
|
+
) -> Thread:
|
|
221
|
+
params = ThreadResumeParams(
|
|
222
|
+
thread_id=thread_id,
|
|
223
|
+
approval_policy=approval_policy,
|
|
224
|
+
approvals_reviewer=approvals_reviewer,
|
|
225
|
+
base_instructions=base_instructions,
|
|
226
|
+
config=config,
|
|
227
|
+
cwd=cwd,
|
|
228
|
+
developer_instructions=developer_instructions,
|
|
229
|
+
model=model,
|
|
230
|
+
model_provider=model_provider,
|
|
231
|
+
personality=personality,
|
|
232
|
+
sandbox=sandbox,
|
|
233
|
+
service_tier=service_tier,
|
|
234
|
+
)
|
|
235
|
+
resumed = self._client.thread_resume(thread_id, params)
|
|
236
|
+
return Thread(self._client, resumed.thread.id)
|
|
237
|
+
|
|
238
|
+
def thread_fork(
|
|
239
|
+
self,
|
|
240
|
+
thread_id: str,
|
|
241
|
+
*,
|
|
242
|
+
approval_policy: AskForApproval | None = None,
|
|
243
|
+
approvals_reviewer: ApprovalsReviewer | None = None,
|
|
244
|
+
base_instructions: str | None = None,
|
|
245
|
+
config: JsonObject | None = None,
|
|
246
|
+
cwd: str | None = None,
|
|
247
|
+
developer_instructions: str | None = None,
|
|
248
|
+
ephemeral: bool | None = None,
|
|
249
|
+
model: str | None = None,
|
|
250
|
+
model_provider: str | None = None,
|
|
251
|
+
sandbox: SandboxMode | None = None,
|
|
252
|
+
service_tier: ServiceTier | None = None,
|
|
253
|
+
) -> Thread:
|
|
254
|
+
params = ThreadForkParams(
|
|
255
|
+
thread_id=thread_id,
|
|
256
|
+
approval_policy=approval_policy,
|
|
257
|
+
approvals_reviewer=approvals_reviewer,
|
|
258
|
+
base_instructions=base_instructions,
|
|
259
|
+
config=config,
|
|
260
|
+
cwd=cwd,
|
|
261
|
+
developer_instructions=developer_instructions,
|
|
262
|
+
ephemeral=ephemeral,
|
|
263
|
+
model=model,
|
|
264
|
+
model_provider=model_provider,
|
|
265
|
+
sandbox=sandbox,
|
|
266
|
+
service_tier=service_tier,
|
|
267
|
+
)
|
|
268
|
+
forked = self._client.thread_fork(thread_id, params)
|
|
269
|
+
return Thread(self._client, forked.thread.id)
|
|
270
|
+
|
|
271
|
+
def thread_archive(self, thread_id: str) -> ThreadArchiveResponse:
|
|
272
|
+
return self._client.thread_archive(thread_id)
|
|
273
|
+
|
|
274
|
+
def thread_unarchive(self, thread_id: str) -> Thread:
|
|
275
|
+
unarchived = self._client.thread_unarchive(thread_id)
|
|
276
|
+
return Thread(self._client, unarchived.thread.id)
|
|
277
|
+
|
|
278
|
+
# END GENERATED: Codex.flat_methods
|
|
279
|
+
|
|
280
|
+
def models(self, *, include_hidden: bool = False) -> ModelListResponse:
|
|
281
|
+
return self._client.model_list(include_hidden=include_hidden)
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
class AsyncCodex:
|
|
285
|
+
"""Async mirror of :class:`Codex`.
|
|
286
|
+
|
|
287
|
+
Prefer ``async with AsyncCodex()`` so initialization and shutdown are
|
|
288
|
+
explicit and paired. The async client initializes lazily on context entry
|
|
289
|
+
or first awaited API use.
|
|
290
|
+
"""
|
|
291
|
+
|
|
292
|
+
def __init__(self, config: AppServerConfig | None = None) -> None:
|
|
293
|
+
self._client = AsyncAppServerClient(config=config)
|
|
294
|
+
self._init: InitializeResponse | None = None
|
|
295
|
+
self._initialized = False
|
|
296
|
+
self._init_lock = asyncio.Lock()
|
|
297
|
+
|
|
298
|
+
async def __aenter__(self) -> "AsyncCodex":
|
|
299
|
+
await self._ensure_initialized()
|
|
300
|
+
return self
|
|
301
|
+
|
|
302
|
+
async def __aexit__(self, _exc_type, _exc, _tb) -> None:
|
|
303
|
+
await self.close()
|
|
304
|
+
|
|
305
|
+
async def _ensure_initialized(self) -> None:
|
|
306
|
+
if self._initialized:
|
|
307
|
+
return
|
|
308
|
+
async with self._init_lock:
|
|
309
|
+
if self._initialized:
|
|
310
|
+
return
|
|
311
|
+
try:
|
|
312
|
+
await self._client.start()
|
|
313
|
+
payload = await self._client.initialize()
|
|
314
|
+
self._init = Codex._validate_initialize(payload)
|
|
315
|
+
self._initialized = True
|
|
316
|
+
except Exception:
|
|
317
|
+
await self._client.close()
|
|
318
|
+
self._init = None
|
|
319
|
+
self._initialized = False
|
|
320
|
+
raise
|
|
321
|
+
|
|
322
|
+
@property
|
|
323
|
+
def metadata(self) -> InitializeResponse:
|
|
324
|
+
if self._init is None:
|
|
325
|
+
raise RuntimeError(
|
|
326
|
+
"AsyncCodex is not initialized yet. Prefer `async with AsyncCodex()`; "
|
|
327
|
+
"initialization also happens on first awaited API use."
|
|
328
|
+
)
|
|
329
|
+
return self._init
|
|
330
|
+
|
|
331
|
+
async def close(self) -> None:
|
|
332
|
+
await self._client.close()
|
|
333
|
+
self._init = None
|
|
334
|
+
self._initialized = False
|
|
335
|
+
|
|
336
|
+
# BEGIN GENERATED: AsyncCodex.flat_methods
|
|
337
|
+
async def thread_start(
|
|
338
|
+
self,
|
|
339
|
+
*,
|
|
340
|
+
approval_policy: AskForApproval | None = None,
|
|
341
|
+
approvals_reviewer: ApprovalsReviewer | None = None,
|
|
342
|
+
base_instructions: str | None = None,
|
|
343
|
+
config: JsonObject | None = None,
|
|
344
|
+
cwd: str | None = None,
|
|
345
|
+
developer_instructions: str | None = None,
|
|
346
|
+
ephemeral: bool | None = None,
|
|
347
|
+
model: str | None = None,
|
|
348
|
+
model_provider: str | None = None,
|
|
349
|
+
personality: Personality | None = None,
|
|
350
|
+
sandbox: SandboxMode | None = None,
|
|
351
|
+
service_name: str | None = None,
|
|
352
|
+
service_tier: ServiceTier | None = None,
|
|
353
|
+
session_start_source: ThreadStartSource | None = None,
|
|
354
|
+
) -> AsyncThread:
|
|
355
|
+
await self._ensure_initialized()
|
|
356
|
+
params = ThreadStartParams(
|
|
357
|
+
approval_policy=approval_policy,
|
|
358
|
+
approvals_reviewer=approvals_reviewer,
|
|
359
|
+
base_instructions=base_instructions,
|
|
360
|
+
config=config,
|
|
361
|
+
cwd=cwd,
|
|
362
|
+
developer_instructions=developer_instructions,
|
|
363
|
+
ephemeral=ephemeral,
|
|
364
|
+
model=model,
|
|
365
|
+
model_provider=model_provider,
|
|
366
|
+
personality=personality,
|
|
367
|
+
sandbox=sandbox,
|
|
368
|
+
service_name=service_name,
|
|
369
|
+
service_tier=service_tier,
|
|
370
|
+
session_start_source=session_start_source,
|
|
371
|
+
)
|
|
372
|
+
started = await self._client.thread_start(params)
|
|
373
|
+
return AsyncThread(self, started.thread.id)
|
|
374
|
+
|
|
375
|
+
async def thread_list(
|
|
376
|
+
self,
|
|
377
|
+
*,
|
|
378
|
+
archived: bool | None = None,
|
|
379
|
+
cursor: str | None = None,
|
|
380
|
+
cwd: ThreadListCwdFilter | None = None,
|
|
381
|
+
limit: int | None = None,
|
|
382
|
+
model_providers: list[str] | None = None,
|
|
383
|
+
search_term: str | None = None,
|
|
384
|
+
sort_direction: SortDirection | None = None,
|
|
385
|
+
sort_key: ThreadSortKey | None = None,
|
|
386
|
+
source_kinds: list[ThreadSourceKind] | None = None,
|
|
387
|
+
use_state_db_only: bool | None = None,
|
|
388
|
+
) -> ThreadListResponse:
|
|
389
|
+
await self._ensure_initialized()
|
|
390
|
+
params = ThreadListParams(
|
|
391
|
+
archived=archived,
|
|
392
|
+
cursor=cursor,
|
|
393
|
+
cwd=cwd,
|
|
394
|
+
limit=limit,
|
|
395
|
+
model_providers=model_providers,
|
|
396
|
+
search_term=search_term,
|
|
397
|
+
sort_direction=sort_direction,
|
|
398
|
+
sort_key=sort_key,
|
|
399
|
+
source_kinds=source_kinds,
|
|
400
|
+
use_state_db_only=use_state_db_only,
|
|
401
|
+
)
|
|
402
|
+
return await self._client.thread_list(params)
|
|
403
|
+
|
|
404
|
+
async def thread_resume(
|
|
405
|
+
self,
|
|
406
|
+
thread_id: str,
|
|
407
|
+
*,
|
|
408
|
+
approval_policy: AskForApproval | None = None,
|
|
409
|
+
approvals_reviewer: ApprovalsReviewer | None = None,
|
|
410
|
+
base_instructions: str | None = None,
|
|
411
|
+
config: JsonObject | None = None,
|
|
412
|
+
cwd: str | None = None,
|
|
413
|
+
developer_instructions: str | None = None,
|
|
414
|
+
model: str | None = None,
|
|
415
|
+
model_provider: str | None = None,
|
|
416
|
+
personality: Personality | None = None,
|
|
417
|
+
sandbox: SandboxMode | None = None,
|
|
418
|
+
service_tier: ServiceTier | None = None,
|
|
419
|
+
) -> AsyncThread:
|
|
420
|
+
await self._ensure_initialized()
|
|
421
|
+
params = ThreadResumeParams(
|
|
422
|
+
thread_id=thread_id,
|
|
423
|
+
approval_policy=approval_policy,
|
|
424
|
+
approvals_reviewer=approvals_reviewer,
|
|
425
|
+
base_instructions=base_instructions,
|
|
426
|
+
config=config,
|
|
427
|
+
cwd=cwd,
|
|
428
|
+
developer_instructions=developer_instructions,
|
|
429
|
+
model=model,
|
|
430
|
+
model_provider=model_provider,
|
|
431
|
+
personality=personality,
|
|
432
|
+
sandbox=sandbox,
|
|
433
|
+
service_tier=service_tier,
|
|
434
|
+
)
|
|
435
|
+
resumed = await self._client.thread_resume(thread_id, params)
|
|
436
|
+
return AsyncThread(self, resumed.thread.id)
|
|
437
|
+
|
|
438
|
+
async def thread_fork(
|
|
439
|
+
self,
|
|
440
|
+
thread_id: str,
|
|
441
|
+
*,
|
|
442
|
+
approval_policy: AskForApproval | None = None,
|
|
443
|
+
approvals_reviewer: ApprovalsReviewer | None = None,
|
|
444
|
+
base_instructions: str | None = None,
|
|
445
|
+
config: JsonObject | None = None,
|
|
446
|
+
cwd: str | None = None,
|
|
447
|
+
developer_instructions: str | None = None,
|
|
448
|
+
ephemeral: bool | None = None,
|
|
449
|
+
model: str | None = None,
|
|
450
|
+
model_provider: str | None = None,
|
|
451
|
+
sandbox: SandboxMode | None = None,
|
|
452
|
+
service_tier: ServiceTier | None = None,
|
|
453
|
+
) -> AsyncThread:
|
|
454
|
+
await self._ensure_initialized()
|
|
455
|
+
params = ThreadForkParams(
|
|
456
|
+
thread_id=thread_id,
|
|
457
|
+
approval_policy=approval_policy,
|
|
458
|
+
approvals_reviewer=approvals_reviewer,
|
|
459
|
+
base_instructions=base_instructions,
|
|
460
|
+
config=config,
|
|
461
|
+
cwd=cwd,
|
|
462
|
+
developer_instructions=developer_instructions,
|
|
463
|
+
ephemeral=ephemeral,
|
|
464
|
+
model=model,
|
|
465
|
+
model_provider=model_provider,
|
|
466
|
+
sandbox=sandbox,
|
|
467
|
+
service_tier=service_tier,
|
|
468
|
+
)
|
|
469
|
+
forked = await self._client.thread_fork(thread_id, params)
|
|
470
|
+
return AsyncThread(self, forked.thread.id)
|
|
471
|
+
|
|
472
|
+
async def thread_archive(self, thread_id: str) -> ThreadArchiveResponse:
|
|
473
|
+
await self._ensure_initialized()
|
|
474
|
+
return await self._client.thread_archive(thread_id)
|
|
475
|
+
|
|
476
|
+
async def thread_unarchive(self, thread_id: str) -> AsyncThread:
|
|
477
|
+
await self._ensure_initialized()
|
|
478
|
+
unarchived = await self._client.thread_unarchive(thread_id)
|
|
479
|
+
return AsyncThread(self, unarchived.thread.id)
|
|
480
|
+
|
|
481
|
+
# END GENERATED: AsyncCodex.flat_methods
|
|
482
|
+
|
|
483
|
+
async def models(self, *, include_hidden: bool = False) -> ModelListResponse:
|
|
484
|
+
await self._ensure_initialized()
|
|
485
|
+
return await self._client.model_list(include_hidden=include_hidden)
|
|
486
|
+
|
|
487
|
+
|
|
488
|
+
@dataclass(slots=True)
|
|
489
|
+
class Thread:
|
|
490
|
+
_client: AppServerClient
|
|
491
|
+
id: str
|
|
492
|
+
|
|
493
|
+
def run(
|
|
494
|
+
self,
|
|
495
|
+
input: RunInput,
|
|
496
|
+
*,
|
|
497
|
+
approval_policy: AskForApproval | None = None,
|
|
498
|
+
approvals_reviewer: ApprovalsReviewer | None = None,
|
|
499
|
+
cwd: str | None = None,
|
|
500
|
+
effort: ReasoningEffort | None = None,
|
|
501
|
+
model: str | None = None,
|
|
502
|
+
output_schema: JsonObject | None = None,
|
|
503
|
+
personality: Personality | None = None,
|
|
504
|
+
sandbox_policy: SandboxPolicy | None = None,
|
|
505
|
+
service_tier: ServiceTier | None = None,
|
|
506
|
+
summary: ReasoningSummary | None = None,
|
|
507
|
+
) -> RunResult:
|
|
508
|
+
turn = self.turn(
|
|
509
|
+
_normalize_run_input(input),
|
|
510
|
+
approval_policy=approval_policy,
|
|
511
|
+
approvals_reviewer=approvals_reviewer,
|
|
512
|
+
cwd=cwd,
|
|
513
|
+
effort=effort,
|
|
514
|
+
model=model,
|
|
515
|
+
output_schema=output_schema,
|
|
516
|
+
personality=personality,
|
|
517
|
+
sandbox_policy=sandbox_policy,
|
|
518
|
+
service_tier=service_tier,
|
|
519
|
+
summary=summary,
|
|
520
|
+
)
|
|
521
|
+
stream = turn.stream()
|
|
522
|
+
try:
|
|
523
|
+
return _collect_run_result(stream, turn_id=turn.id)
|
|
524
|
+
finally:
|
|
525
|
+
stream.close()
|
|
526
|
+
|
|
527
|
+
# BEGIN GENERATED: Thread.flat_methods
|
|
528
|
+
def turn(
|
|
529
|
+
self,
|
|
530
|
+
input: Input,
|
|
531
|
+
*,
|
|
532
|
+
approval_policy: AskForApproval | None = None,
|
|
533
|
+
approvals_reviewer: ApprovalsReviewer | None = None,
|
|
534
|
+
cwd: str | None = None,
|
|
535
|
+
effort: ReasoningEffort | None = None,
|
|
536
|
+
model: str | None = None,
|
|
537
|
+
output_schema: JsonObject | None = None,
|
|
538
|
+
personality: Personality | None = None,
|
|
539
|
+
sandbox_policy: SandboxPolicy | None = None,
|
|
540
|
+
service_tier: ServiceTier | None = None,
|
|
541
|
+
summary: ReasoningSummary | None = None,
|
|
542
|
+
) -> TurnHandle:
|
|
543
|
+
wire_input = _to_wire_input(input)
|
|
544
|
+
params = TurnStartParams(
|
|
545
|
+
thread_id=self.id,
|
|
546
|
+
input=wire_input,
|
|
547
|
+
approval_policy=approval_policy,
|
|
548
|
+
approvals_reviewer=approvals_reviewer,
|
|
549
|
+
cwd=cwd,
|
|
550
|
+
effort=effort,
|
|
551
|
+
model=model,
|
|
552
|
+
output_schema=output_schema,
|
|
553
|
+
personality=personality,
|
|
554
|
+
sandbox_policy=sandbox_policy,
|
|
555
|
+
service_tier=service_tier,
|
|
556
|
+
summary=summary,
|
|
557
|
+
)
|
|
558
|
+
turn = self._client.turn_start(self.id, wire_input, params=params)
|
|
559
|
+
return TurnHandle(self._client, self.id, turn.turn.id)
|
|
560
|
+
|
|
561
|
+
# END GENERATED: Thread.flat_methods
|
|
562
|
+
|
|
563
|
+
def read(self, *, include_turns: bool = False) -> ThreadReadResponse:
|
|
564
|
+
return self._client.thread_read(self.id, include_turns=include_turns)
|
|
565
|
+
|
|
566
|
+
def set_name(self, name: str) -> ThreadSetNameResponse:
|
|
567
|
+
return self._client.thread_set_name(self.id, name)
|
|
568
|
+
|
|
569
|
+
def compact(self) -> ThreadCompactStartResponse:
|
|
570
|
+
return self._client.thread_compact(self.id)
|
|
571
|
+
|
|
572
|
+
|
|
573
|
+
@dataclass(slots=True)
|
|
574
|
+
class AsyncThread:
|
|
575
|
+
_codex: AsyncCodex
|
|
576
|
+
id: str
|
|
577
|
+
|
|
578
|
+
async def run(
|
|
579
|
+
self,
|
|
580
|
+
input: RunInput,
|
|
581
|
+
*,
|
|
582
|
+
approval_policy: AskForApproval | None = None,
|
|
583
|
+
approvals_reviewer: ApprovalsReviewer | None = None,
|
|
584
|
+
cwd: str | None = None,
|
|
585
|
+
effort: ReasoningEffort | None = None,
|
|
586
|
+
model: str | None = None,
|
|
587
|
+
output_schema: JsonObject | None = None,
|
|
588
|
+
personality: Personality | None = None,
|
|
589
|
+
sandbox_policy: SandboxPolicy | None = None,
|
|
590
|
+
service_tier: ServiceTier | None = None,
|
|
591
|
+
summary: ReasoningSummary | None = None,
|
|
592
|
+
) -> RunResult:
|
|
593
|
+
turn = await self.turn(
|
|
594
|
+
_normalize_run_input(input),
|
|
595
|
+
approval_policy=approval_policy,
|
|
596
|
+
approvals_reviewer=approvals_reviewer,
|
|
597
|
+
cwd=cwd,
|
|
598
|
+
effort=effort,
|
|
599
|
+
model=model,
|
|
600
|
+
output_schema=output_schema,
|
|
601
|
+
personality=personality,
|
|
602
|
+
sandbox_policy=sandbox_policy,
|
|
603
|
+
service_tier=service_tier,
|
|
604
|
+
summary=summary,
|
|
605
|
+
)
|
|
606
|
+
stream = turn.stream()
|
|
607
|
+
try:
|
|
608
|
+
return await _collect_async_run_result(stream, turn_id=turn.id)
|
|
609
|
+
finally:
|
|
610
|
+
await stream.aclose()
|
|
611
|
+
|
|
612
|
+
# BEGIN GENERATED: AsyncThread.flat_methods
|
|
613
|
+
async def turn(
|
|
614
|
+
self,
|
|
615
|
+
input: Input,
|
|
616
|
+
*,
|
|
617
|
+
approval_policy: AskForApproval | None = None,
|
|
618
|
+
approvals_reviewer: ApprovalsReviewer | None = None,
|
|
619
|
+
cwd: str | None = None,
|
|
620
|
+
effort: ReasoningEffort | None = None,
|
|
621
|
+
model: str | None = None,
|
|
622
|
+
output_schema: JsonObject | None = None,
|
|
623
|
+
personality: Personality | None = None,
|
|
624
|
+
sandbox_policy: SandboxPolicy | None = None,
|
|
625
|
+
service_tier: ServiceTier | None = None,
|
|
626
|
+
summary: ReasoningSummary | None = None,
|
|
627
|
+
) -> AsyncTurnHandle:
|
|
628
|
+
await self._codex._ensure_initialized()
|
|
629
|
+
wire_input = _to_wire_input(input)
|
|
630
|
+
params = TurnStartParams(
|
|
631
|
+
thread_id=self.id,
|
|
632
|
+
input=wire_input,
|
|
633
|
+
approval_policy=approval_policy,
|
|
634
|
+
approvals_reviewer=approvals_reviewer,
|
|
635
|
+
cwd=cwd,
|
|
636
|
+
effort=effort,
|
|
637
|
+
model=model,
|
|
638
|
+
output_schema=output_schema,
|
|
639
|
+
personality=personality,
|
|
640
|
+
sandbox_policy=sandbox_policy,
|
|
641
|
+
service_tier=service_tier,
|
|
642
|
+
summary=summary,
|
|
643
|
+
)
|
|
644
|
+
turn = await self._codex._client.turn_start(
|
|
645
|
+
self.id,
|
|
646
|
+
wire_input,
|
|
647
|
+
params=params,
|
|
648
|
+
)
|
|
649
|
+
return AsyncTurnHandle(self._codex, self.id, turn.turn.id)
|
|
650
|
+
|
|
651
|
+
# END GENERATED: AsyncThread.flat_methods
|
|
652
|
+
|
|
653
|
+
async def read(self, *, include_turns: bool = False) -> ThreadReadResponse:
|
|
654
|
+
await self._codex._ensure_initialized()
|
|
655
|
+
return await self._codex._client.thread_read(
|
|
656
|
+
self.id, include_turns=include_turns
|
|
657
|
+
)
|
|
658
|
+
|
|
659
|
+
async def set_name(self, name: str) -> ThreadSetNameResponse:
|
|
660
|
+
await self._codex._ensure_initialized()
|
|
661
|
+
return await self._codex._client.thread_set_name(self.id, name)
|
|
662
|
+
|
|
663
|
+
async def compact(self) -> ThreadCompactStartResponse:
|
|
664
|
+
await self._codex._ensure_initialized()
|
|
665
|
+
return await self._codex._client.thread_compact(self.id)
|
|
666
|
+
|
|
667
|
+
|
|
668
|
+
@dataclass(slots=True)
|
|
669
|
+
class TurnHandle:
|
|
670
|
+
_client: AppServerClient
|
|
671
|
+
thread_id: str
|
|
672
|
+
id: str
|
|
673
|
+
|
|
674
|
+
def steer(self, input: Input) -> TurnSteerResponse:
|
|
675
|
+
return self._client.turn_steer(self.thread_id, self.id, _to_wire_input(input))
|
|
676
|
+
|
|
677
|
+
def interrupt(self) -> TurnInterruptResponse:
|
|
678
|
+
return self._client.turn_interrupt(self.thread_id, self.id)
|
|
679
|
+
|
|
680
|
+
def stream(self) -> Iterator[Notification]:
|
|
681
|
+
self._client.register_turn_notifications(self.id)
|
|
682
|
+
try:
|
|
683
|
+
while True:
|
|
684
|
+
event = self._client.next_turn_notification(self.id)
|
|
685
|
+
yield event
|
|
686
|
+
if (
|
|
687
|
+
event.method == "turn/completed"
|
|
688
|
+
and isinstance(event.payload, TurnCompletedNotification)
|
|
689
|
+
and event.payload.turn.id == self.id
|
|
690
|
+
):
|
|
691
|
+
break
|
|
692
|
+
finally:
|
|
693
|
+
self._client.unregister_turn_notifications(self.id)
|
|
694
|
+
|
|
695
|
+
def run(self) -> AppServerTurn:
|
|
696
|
+
completed: TurnCompletedNotification | None = None
|
|
697
|
+
stream = self.stream()
|
|
698
|
+
try:
|
|
699
|
+
for event in stream:
|
|
700
|
+
payload = event.payload
|
|
701
|
+
if (
|
|
702
|
+
isinstance(payload, TurnCompletedNotification)
|
|
703
|
+
and payload.turn.id == self.id
|
|
704
|
+
):
|
|
705
|
+
completed = payload
|
|
706
|
+
finally:
|
|
707
|
+
stream.close()
|
|
708
|
+
|
|
709
|
+
if completed is None:
|
|
710
|
+
raise RuntimeError("turn completed event not received")
|
|
711
|
+
return completed.turn
|
|
712
|
+
|
|
713
|
+
|
|
714
|
+
@dataclass(slots=True)
|
|
715
|
+
class AsyncTurnHandle:
|
|
716
|
+
_codex: AsyncCodex
|
|
717
|
+
thread_id: str
|
|
718
|
+
id: str
|
|
719
|
+
|
|
720
|
+
async def steer(self, input: Input) -> TurnSteerResponse:
|
|
721
|
+
await self._codex._ensure_initialized()
|
|
722
|
+
return await self._codex._client.turn_steer(
|
|
723
|
+
self.thread_id,
|
|
724
|
+
self.id,
|
|
725
|
+
_to_wire_input(input),
|
|
726
|
+
)
|
|
727
|
+
|
|
728
|
+
async def interrupt(self) -> TurnInterruptResponse:
|
|
729
|
+
await self._codex._ensure_initialized()
|
|
730
|
+
return await self._codex._client.turn_interrupt(self.thread_id, self.id)
|
|
731
|
+
|
|
732
|
+
async def stream(self) -> AsyncIterator[Notification]:
|
|
733
|
+
await self._codex._ensure_initialized()
|
|
734
|
+
self._codex._client.register_turn_notifications(self.id)
|
|
735
|
+
try:
|
|
736
|
+
while True:
|
|
737
|
+
event = await self._codex._client.next_turn_notification(self.id)
|
|
738
|
+
yield event
|
|
739
|
+
if (
|
|
740
|
+
event.method == "turn/completed"
|
|
741
|
+
and isinstance(event.payload, TurnCompletedNotification)
|
|
742
|
+
and event.payload.turn.id == self.id
|
|
743
|
+
):
|
|
744
|
+
break
|
|
745
|
+
finally:
|
|
746
|
+
self._codex._client.unregister_turn_notifications(self.id)
|
|
747
|
+
|
|
748
|
+
async def run(self) -> AppServerTurn:
|
|
749
|
+
completed: TurnCompletedNotification | None = None
|
|
750
|
+
stream = self.stream()
|
|
751
|
+
try:
|
|
752
|
+
async for event in stream:
|
|
753
|
+
payload = event.payload
|
|
754
|
+
if (
|
|
755
|
+
isinstance(payload, TurnCompletedNotification)
|
|
756
|
+
and payload.turn.id == self.id
|
|
757
|
+
):
|
|
758
|
+
completed = payload
|
|
759
|
+
finally:
|
|
760
|
+
await stream.aclose()
|
|
761
|
+
|
|
762
|
+
if completed is None:
|
|
763
|
+
raise RuntimeError("turn completed event not received")
|
|
764
|
+
return completed.turn
|