codex-python 1.122.0__tar.gz → 1.131.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {codex_python-1.122.0 → codex_python-1.131.1}/PKG-INFO +1 -1
- {codex_python-1.122.0 → codex_python-1.131.1}/codex/__init__.py +1 -1
- {codex_python-1.122.0 → codex_python-1.131.1}/codex/app_server/_async_client.py +30 -1
- {codex_python-1.122.0 → codex_python-1.131.1}/codex/app_server/_async_services.py +0 -6
- {codex_python-1.122.0 → codex_python-1.131.1}/codex/app_server/_async_threads.py +25 -0
- {codex_python-1.122.0 → codex_python-1.131.1}/codex/app_server/_protocol_helpers.py +9 -3
- {codex_python-1.122.0 → codex_python-1.131.1}/codex/app_server/_sync_services.py +0 -6
- {codex_python-1.122.0 → codex_python-1.131.1}/codex/app_server/_sync_threads.py +18 -0
- {codex_python-1.122.0 → codex_python-1.131.1}/codex/protocol/types.py +2195 -570
- {codex_python-1.122.0 → codex_python-1.131.1}/crates/codex_native/Cargo.lock +3 -3
- {codex_python-1.122.0 → codex_python-1.131.1}/crates/codex_native/Cargo.toml +1 -1
- {codex_python-1.122.0 → codex_python-1.131.1}/LICENSE +0 -0
- {codex_python-1.122.0 → codex_python-1.131.1}/README.md +0 -0
- {codex_python-1.122.0 → codex_python-1.131.1}/codex/_binary.py +0 -0
- {codex_python-1.122.0 → codex_python-1.131.1}/codex/_config_types.py +0 -0
- {codex_python-1.122.0 → codex_python-1.131.1}/codex/_file_utils.py +0 -0
- {codex_python-1.122.0 → codex_python-1.131.1}/codex/_runtime.py +0 -0
- {codex_python-1.122.0 → codex_python-1.131.1}/codex/_turn_options.py +0 -0
- {codex_python-1.122.0 → codex_python-1.131.1}/codex/app_server/__init__.py +0 -0
- {codex_python-1.122.0 → codex_python-1.131.1}/codex/app_server/_payloads.py +0 -0
- {codex_python-1.122.0 → codex_python-1.131.1}/codex/app_server/_session.py +0 -0
- {codex_python-1.122.0 → codex_python-1.131.1}/codex/app_server/_sync_client.py +0 -0
- {codex_python-1.122.0 → codex_python-1.131.1}/codex/app_server/_sync_support.py +0 -0
- {codex_python-1.122.0 → codex_python-1.131.1}/codex/app_server/_types.py +0 -0
- {codex_python-1.122.0 → codex_python-1.131.1}/codex/app_server/errors.py +0 -0
- {codex_python-1.122.0 → codex_python-1.131.1}/codex/app_server/models.py +0 -0
- {codex_python-1.122.0 → codex_python-1.131.1}/codex/app_server/options.py +0 -0
- {codex_python-1.122.0 → codex_python-1.131.1}/codex/app_server/transports.py +0 -0
- {codex_python-1.122.0 → codex_python-1.131.1}/codex/codex.py +0 -0
- {codex_python-1.122.0 → codex_python-1.131.1}/codex/dynamic_tools.py +0 -0
- {codex_python-1.122.0 → codex_python-1.131.1}/codex/errors.py +0 -0
- {codex_python-1.122.0 → codex_python-1.131.1}/codex/options.py +0 -0
- {codex_python-1.122.0 → codex_python-1.131.1}/codex/output_schema.py +0 -0
- {codex_python-1.122.0 → codex_python-1.131.1}/codex/output_schema_file.py +0 -0
- {codex_python-1.122.0 → codex_python-1.131.1}/codex/protocol/__init__.py +0 -0
- {codex_python-1.122.0 → codex_python-1.131.1}/codex/py.typed +0 -0
- {codex_python-1.122.0 → codex_python-1.131.1}/codex/thread.py +0 -0
- {codex_python-1.122.0 → codex_python-1.131.1}/codex/vendor/.gitkeep +0 -0
- {codex_python-1.122.0 → codex_python-1.131.1}/crates/codex_native/codex/__init__.py +0 -0
- {codex_python-1.122.0 → codex_python-1.131.1}/crates/codex_native/src/lib.rs +0 -0
- {codex_python-1.122.0 → codex_python-1.131.1}/pyproject.toml +0 -0
|
@@ -22,7 +22,7 @@ from codex.app_server._async_services import (
|
|
|
22
22
|
from codex.app_server._async_threads import AsyncAppServerThread as AsyncAppServerThread
|
|
23
23
|
from codex.app_server._async_threads import AsyncTurnStream as AsyncTurnStream
|
|
24
24
|
from codex.app_server._async_threads import _ThreadClient
|
|
25
|
-
from codex.app_server._protocol_helpers import RequestHandler
|
|
25
|
+
from codex.app_server._protocol_helpers import Notification, RequestHandler
|
|
26
26
|
from codex.app_server._session import _AsyncNotificationSubscription, _AsyncSession
|
|
27
27
|
from codex.app_server.models import (
|
|
28
28
|
InitializeResult,
|
|
@@ -107,6 +107,35 @@ class AsyncEventsClient:
|
|
|
107
107
|
def subscribe(self, methods: Collection[str] | None = None) -> _AsyncNotificationSubscription:
|
|
108
108
|
return self._session.subscribe_notifications(methods)
|
|
109
109
|
|
|
110
|
+
def subscribe_command_exec_output(self, process_id: str) -> _AsyncNotificationSubscription:
|
|
111
|
+
"""Subscribe to `command/exec/outputDelta` notifications for one process id."""
|
|
112
|
+
|
|
113
|
+
def predicate(notification: Notification) -> bool:
|
|
114
|
+
return (
|
|
115
|
+
isinstance(notification, protocol.CommandExecOutputDeltaNotificationModel)
|
|
116
|
+
and notification.params.processId == process_id
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
return self._session.subscribe_notifications(
|
|
120
|
+
{"command/exec/outputDelta"},
|
|
121
|
+
predicate=predicate,
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
def subscribe_process_events(self, process_handle: str) -> _AsyncNotificationSubscription:
|
|
125
|
+
"""Subscribe to `process/outputDelta` and `process/exited` for one process handle."""
|
|
126
|
+
|
|
127
|
+
def predicate(notification: Notification) -> bool:
|
|
128
|
+
if isinstance(notification, protocol.ProcessOutputDeltaNotificationModel):
|
|
129
|
+
return notification.params.processHandle == process_handle
|
|
130
|
+
if isinstance(notification, protocol.ProcessExitedNotificationModel):
|
|
131
|
+
return notification.params.processHandle == process_handle
|
|
132
|
+
return False
|
|
133
|
+
|
|
134
|
+
return self._session.subscribe_notifications(
|
|
135
|
+
{"process/outputDelta", "process/exited"},
|
|
136
|
+
predicate=predicate,
|
|
137
|
+
)
|
|
138
|
+
|
|
110
139
|
|
|
111
140
|
class AsyncAppServerClient:
|
|
112
141
|
"""Async client for `codex app-server`."""
|
|
@@ -113,13 +113,11 @@ class AsyncSkillsClient(_AsyncServiceClient):
|
|
|
113
113
|
*,
|
|
114
114
|
cwds: Sequence[str] | None = None,
|
|
115
115
|
force_reload: bool | None = None,
|
|
116
|
-
per_cwd_extra_user_roots: Sequence[protocol.SkillsListExtraRootsForCwd] | None = None,
|
|
117
116
|
) -> list[SkillsListEntry]:
|
|
118
117
|
return (
|
|
119
118
|
await self.list_page(
|
|
120
119
|
cwds=cwds,
|
|
121
120
|
force_reload=force_reload,
|
|
122
|
-
per_cwd_extra_user_roots=per_cwd_extra_user_roots,
|
|
123
121
|
)
|
|
124
122
|
).data
|
|
125
123
|
|
|
@@ -128,14 +126,10 @@ class AsyncSkillsClient(_AsyncServiceClient):
|
|
|
128
126
|
*,
|
|
129
127
|
cwds: Sequence[str] | None = None,
|
|
130
128
|
force_reload: bool | None = None,
|
|
131
|
-
per_cwd_extra_user_roots: Sequence[protocol.SkillsListExtraRootsForCwd] | None = None,
|
|
132
129
|
) -> SkillsListResult:
|
|
133
130
|
params = protocol.SkillsListParams(
|
|
134
131
|
cwds=list(cwds) if cwds is not None else None,
|
|
135
132
|
forceReload=force_reload,
|
|
136
|
-
perCwdExtraUserRoots=(
|
|
137
|
-
list(per_cwd_extra_user_roots) if per_cwd_extra_user_roots is not None else None
|
|
138
|
-
),
|
|
139
133
|
)
|
|
140
134
|
return await self._rpc.request_typed("skills/list", params, SkillsListResult)
|
|
141
135
|
|
|
@@ -37,6 +37,7 @@ _ModelT = TypeVar("_ModelT", bound=BaseModel)
|
|
|
37
37
|
DEFAULT_REVIEW_DELIVERY = protocol.ReviewDelivery("inline")
|
|
38
38
|
|
|
39
39
|
_TURN_STREAM_NOTIFICATION_METHODS = {
|
|
40
|
+
"error",
|
|
40
41
|
"turn/started",
|
|
41
42
|
"turn/completed",
|
|
42
43
|
"turn/diff/updated",
|
|
@@ -54,6 +55,7 @@ _TURN_STREAM_NOTIFICATION_METHODS = {
|
|
|
54
55
|
"item/reasoning/summaryPartAdded",
|
|
55
56
|
"item/reasoning/textDelta",
|
|
56
57
|
"item/commandExecution/outputDelta",
|
|
58
|
+
"item/commandExecution/terminalInteraction",
|
|
57
59
|
"item/fileChange/outputDelta",
|
|
58
60
|
"serverRequest/resolved",
|
|
59
61
|
}
|
|
@@ -132,6 +134,7 @@ class AsyncTurnStream:
|
|
|
132
134
|
self.usage: protocol.ThreadTokenUsage | None = None
|
|
133
135
|
self._item_index: dict[str, int] = {}
|
|
134
136
|
self._text_deltas: list[str] = []
|
|
137
|
+
self._retryable_error_notifications: list[protocol.ErrorNotificationModel] = []
|
|
135
138
|
self._done = False
|
|
136
139
|
self._closed = False
|
|
137
140
|
|
|
@@ -188,6 +191,16 @@ class AsyncTurnStream:
|
|
|
188
191
|
raise StopAsyncIteration
|
|
189
192
|
notification = await self._subscription.next()
|
|
190
193
|
self._apply(notification)
|
|
194
|
+
if isinstance(notification, protocol.ErrorNotificationModel):
|
|
195
|
+
if not notification.params.willRetry:
|
|
196
|
+
self._done = True
|
|
197
|
+
await self.close()
|
|
198
|
+
error = notification.params.error
|
|
199
|
+
message = error.message
|
|
200
|
+
if error.additionalDetails is not None and error.additionalDetails != "":
|
|
201
|
+
message = f"{message}: {error.additionalDetails}"
|
|
202
|
+
raise AppServerTurnError(message)
|
|
203
|
+
self._retryable_error_notifications.append(notification)
|
|
191
204
|
if isinstance(notification, protocol.TurnCompletedNotificationModel):
|
|
192
205
|
self._done = True
|
|
193
206
|
return notification
|
|
@@ -274,6 +287,18 @@ class AsyncTurnStream:
|
|
|
274
287
|
"""Return the streamed agent text deltas received so far."""
|
|
275
288
|
return tuple(self._text_deltas)
|
|
276
289
|
|
|
290
|
+
@property
|
|
291
|
+
def retryable_error_notifications(self) -> tuple[protocol.ErrorNotificationModel, ...]:
|
|
292
|
+
"""Return retryable turn error notifications received so far."""
|
|
293
|
+
return tuple(self._retryable_error_notifications)
|
|
294
|
+
|
|
295
|
+
@property
|
|
296
|
+
def retryable_errors(self) -> tuple[protocol.TurnError, ...]:
|
|
297
|
+
"""Return retryable turn errors received so far."""
|
|
298
|
+
return tuple(
|
|
299
|
+
notification.params.error for notification in self._retryable_error_notifications
|
|
300
|
+
)
|
|
301
|
+
|
|
277
302
|
def _apply(self, notification: Notification) -> None:
|
|
278
303
|
self._apply_text_delta(notification)
|
|
279
304
|
self._apply_token_usage(notification)
|
|
@@ -12,7 +12,8 @@ from codex.app_server.models import GenericNotification, GenericServerRequest
|
|
|
12
12
|
from codex.protocol import types as protocol
|
|
13
13
|
|
|
14
14
|
type RequestHandler[RequestT: BaseModel] = Callable[[RequestT], object | Awaitable[object]]
|
|
15
|
-
Notification =
|
|
15
|
+
type Notification = protocol.ServerNotificationValue | GenericNotification
|
|
16
|
+
type ServerRequest = protocol.ServerRequestValue | GenericServerRequest
|
|
16
17
|
|
|
17
18
|
|
|
18
19
|
def method_name(message: BaseModel) -> str:
|
|
@@ -123,7 +124,7 @@ def parse_notification(message: JsonObject, *, strict: bool) -> Notification:
|
|
|
123
124
|
raise AppServerProtocolError(_notification_error_message(message)) from exc
|
|
124
125
|
|
|
125
126
|
|
|
126
|
-
def parse_server_request(message: JsonObject, *, strict: bool) ->
|
|
127
|
+
def parse_server_request(message: JsonObject, *, strict: bool) -> ServerRequest:
|
|
127
128
|
method = message.get("method")
|
|
128
129
|
try:
|
|
129
130
|
return protocol.ServerRequest.model_validate(message).root
|
|
@@ -151,9 +152,10 @@ def _build_known_methods(*, root_model: type[BaseModel]) -> frozenset[str]:
|
|
|
151
152
|
root_field = getattr(root_model, "model_fields", {}).get("root")
|
|
152
153
|
if root_field is None:
|
|
153
154
|
return frozenset()
|
|
155
|
+
annotation = _unwrap_type_alias(root_field.annotation)
|
|
154
156
|
methods = {
|
|
155
157
|
method
|
|
156
|
-
for candidate in get_args(
|
|
158
|
+
for candidate in get_args(annotation)
|
|
157
159
|
if isinstance(candidate, type) and issubclass(candidate, BaseModel)
|
|
158
160
|
for method in [_candidate_method_literal(candidate)]
|
|
159
161
|
if method is not None
|
|
@@ -161,6 +163,10 @@ def _build_known_methods(*, root_model: type[BaseModel]) -> frozenset[str]:
|
|
|
161
163
|
return frozenset(methods)
|
|
162
164
|
|
|
163
165
|
|
|
166
|
+
def _unwrap_type_alias(annotation: object) -> object:
|
|
167
|
+
return getattr(annotation, "__value__", annotation)
|
|
168
|
+
|
|
169
|
+
|
|
164
170
|
def _candidate_method_literal(candidate: type[BaseModel]) -> str | None:
|
|
165
171
|
model_fields = getattr(candidate, "model_fields", None)
|
|
166
172
|
if not isinstance(model_fields, dict) or "method" not in model_fields:
|
|
@@ -76,7 +76,6 @@ class _AsyncSkillsClientLike(Protocol):
|
|
|
76
76
|
*,
|
|
77
77
|
cwds: Sequence[str] | None = None,
|
|
78
78
|
force_reload: bool | None = None,
|
|
79
|
-
per_cwd_extra_user_roots: Sequence[protocol.SkillsListExtraRootsForCwd] | None = None,
|
|
80
79
|
) -> list[SkillsListEntry]: ...
|
|
81
80
|
|
|
82
81
|
async def list_page(
|
|
@@ -84,7 +83,6 @@ class _AsyncSkillsClientLike(Protocol):
|
|
|
84
83
|
*,
|
|
85
84
|
cwds: Sequence[str] | None = None,
|
|
86
85
|
force_reload: bool | None = None,
|
|
87
|
-
per_cwd_extra_user_roots: Sequence[protocol.SkillsListExtraRootsForCwd] | None = None,
|
|
88
86
|
) -> SkillsListResult: ...
|
|
89
87
|
|
|
90
88
|
async def write_config(self, *, path: str, enabled: bool) -> SkillsConfigWriteResult: ...
|
|
@@ -338,13 +336,11 @@ class _SkillsClient(_SyncRunner):
|
|
|
338
336
|
*,
|
|
339
337
|
cwds: Sequence[str] | None = None,
|
|
340
338
|
force_reload: bool | None = None,
|
|
341
|
-
per_cwd_extra_user_roots: Sequence[protocol.SkillsListExtraRootsForCwd] | None = None,
|
|
342
339
|
) -> list[SkillsListEntry]:
|
|
343
340
|
return self._run(
|
|
344
341
|
self._async_client.list(
|
|
345
342
|
cwds=cwds,
|
|
346
343
|
force_reload=force_reload,
|
|
347
|
-
per_cwd_extra_user_roots=per_cwd_extra_user_roots,
|
|
348
344
|
)
|
|
349
345
|
)
|
|
350
346
|
|
|
@@ -353,13 +349,11 @@ class _SkillsClient(_SyncRunner):
|
|
|
353
349
|
*,
|
|
354
350
|
cwds: Sequence[str] | None = None,
|
|
355
351
|
force_reload: bool | None = None,
|
|
356
|
-
per_cwd_extra_user_roots: Sequence[protocol.SkillsListExtraRootsForCwd] | None = None,
|
|
357
352
|
) -> SkillsListResult:
|
|
358
353
|
return self._run(
|
|
359
354
|
self._async_client.list_page(
|
|
360
355
|
cwds=cwds,
|
|
361
356
|
force_reload=force_reload,
|
|
362
|
-
per_cwd_extra_user_roots=per_cwd_extra_user_roots,
|
|
363
357
|
)
|
|
364
358
|
)
|
|
365
359
|
|
|
@@ -25,6 +25,10 @@ class _AsyncEventsClientLike(Protocol):
|
|
|
25
25
|
methods: Collection[str] | None = None,
|
|
26
26
|
) -> _AsyncNotificationSubscription: ...
|
|
27
27
|
|
|
28
|
+
def subscribe_command_exec_output(self, process_id: str) -> _AsyncNotificationSubscription: ...
|
|
29
|
+
|
|
30
|
+
def subscribe_process_events(self, process_handle: str) -> _AsyncNotificationSubscription: ...
|
|
31
|
+
|
|
28
32
|
|
|
29
33
|
class _AsyncTurnStreamLike(Protocol):
|
|
30
34
|
initial_turn: protocol.Turn
|
|
@@ -157,6 +161,20 @@ class EventsClient(_SyncRunner):
|
|
|
157
161
|
self._run,
|
|
158
162
|
)
|
|
159
163
|
|
|
164
|
+
def subscribe_command_exec_output(self, process_id: str) -> NotificationSubscription:
|
|
165
|
+
"""Subscribe to `command/exec/outputDelta` notifications for one process id."""
|
|
166
|
+
return NotificationSubscription(
|
|
167
|
+
self._async_events.subscribe_command_exec_output(process_id),
|
|
168
|
+
self._run,
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
def subscribe_process_events(self, process_handle: str) -> NotificationSubscription:
|
|
172
|
+
"""Subscribe to `process/outputDelta` and `process/exited` for one process handle."""
|
|
173
|
+
return NotificationSubscription(
|
|
174
|
+
self._async_events.subscribe_process_events(process_handle),
|
|
175
|
+
self._run,
|
|
176
|
+
)
|
|
177
|
+
|
|
160
178
|
|
|
161
179
|
class TurnStream(_SyncRunner):
|
|
162
180
|
"""Synchronous iterator over protocol-native notifications for a single turn."""
|