python-sdk: prepare openai-codex package

This commit is contained in:
Shaqayeq
2026-04-12 23:17:46 -07:00
parent f412b39118
commit 8748ac15ca
9 changed files with 618 additions and 106 deletions

View File

@@ -11,10 +11,16 @@ cd sdk/python
python -m pip install -e .
```
Published SDK builds pin an exact `codex-cli-bin` runtime dependency. For local
repo development, either pass `AppServerConfig(codex_bin=...)` to point at a
local build explicitly, or use the repo examples/notebook bootstrap which
installs the pinned runtime package automatically.
Published SDK builds pin an exact `openai-codex-cli-bin` runtime dependency.
For local repo development, either pass `AppServerConfig(codex_bin=...)` to
point at a local build explicitly, or use the repo examples/notebook bootstrap
which installs the pinned runtime package automatically.
When published, normal installs should use:
```bash
python -m pip install openai-codex
```
## Quickstart
@@ -53,9 +59,9 @@ python examples/01_quickstart_constructor/async.py
The repo no longer checks `codex` binaries into `sdk/python`.
Published SDK builds are pinned to an exact `codex-cli-bin` package version,
and that runtime package carries the platform-specific binary for the target
wheel.
Published SDK builds are pinned to an exact `openai-codex-cli-bin` package
version, and that runtime package carries the platform-specific binary bundle
for the target wheel.
For local repo development, the checked-in `sdk/python-runtime` package is only
a template for staged release artifacts. Editable installs should use an
@@ -69,30 +75,33 @@ cd sdk/python
python scripts/update_sdk_artifacts.py generate-types
python scripts/update_sdk_artifacts.py \
stage-sdk \
/tmp/codex-python-release/codex-app-server-sdk \
/tmp/codex-python-release/openai-codex \
--runtime-version 1.2.3
python scripts/update_sdk_artifacts.py \
stage-runtime \
/tmp/codex-python-release/codex-cli-bin \
/path/to/codex \
/tmp/codex-python-release/openai-codex-cli-bin \
/path/to/runtime-bundle-dir \
--runtime-version 1.2.3
```
This supports the CI release flow:
- run `generate-types` before packaging
- stage `codex-app-server-sdk` once with an exact `codex-cli-bin==...` dependency
- stage `codex-cli-bin` on each supported platform runner with the same pinned runtime version
- build and publish `codex-cli-bin` as platform wheels only; do not publish an sdist
- stage `openai-codex` once with an exact `openai-codex-cli-bin==...` dependency
- stage `openai-codex-cli-bin` on each supported platform runner with the same pinned runtime version
- build and publish `openai-codex-cli-bin` as platform wheels only; do not publish an sdist
## Compatibility and versioning
- Package: `codex-app-server-sdk`
- Runtime package: `codex-cli-bin`
- Package: `openai-codex`
- Runtime package: `openai-codex-cli-bin`
- Current SDK version in this repo: `0.2.0`
- Python: `>=3.10`
- Target protocol: Codex `app-server` JSON-RPC v2
- Recommendation: keep SDK and `codex` CLI reasonably up to date together
- Release tags map to Python package versions as follows: `rust-v1.2.3` ->
`1.2.3`, `rust-v1.2.3-alpha.4` -> `1.2.3a4`, and
`rust-v1.2.3-beta.5` -> `1.2.3b5`.
- Recommendation: keep SDK and `codex` CLI at the exact same published version.
## Notes

View File

@@ -54,26 +54,26 @@ This avoids duplicate ways to do the same operation and keeps behavior explicit.
Common causes:
- published runtime package (`codex-cli-bin`) is not installed
- published runtime package (`openai-codex-cli-bin`) is not installed
- local `codex_bin` override points to a missing file
- local auth/session is missing
- incompatible/old app-server
Maintainers stage releases by building the SDK once and the runtime once per
platform with the same pinned runtime version. Publish `codex-cli-bin` as
platform wheels only; do not publish an sdist:
platform with the same pinned runtime version. Publish `openai-codex-cli-bin`
as platform wheels only; do not publish an sdist:
```bash
cd sdk/python
python scripts/update_sdk_artifacts.py generate-types
python scripts/update_sdk_artifacts.py \
stage-sdk \
/tmp/codex-python-release/codex-app-server-sdk \
/tmp/codex-python-release/openai-codex \
--runtime-version 1.2.3
python scripts/update_sdk_artifacts.py \
stage-runtime \
/tmp/codex-python-release/codex-cli-bin \
/path/to/codex \
/tmp/codex-python-release/openai-codex-cli-bin \
/path/to/runtime-bundle-dir \
--runtime-version 1.2.3
```

View File

@@ -16,7 +16,7 @@ python -m pip install -e .
Requirements:
- Python `>=3.10`
- installed `codex-cli-bin` runtime package, or an explicit `codex_bin` override
- installed `openai-codex-cli-bin` runtime package, or an explicit `codex_bin` override
- local Codex auth/session configured
## 2) Run your first turn (sync)

View File

@@ -23,12 +23,12 @@ python -m pip install -e .
When running examples from this repo checkout, the SDK source uses the local
tree and does not bundle a runtime binary. The helper in `examples/_bootstrap.py`
uses the installed `codex-cli-bin` runtime package.
uses the installed `openai-codex-cli-bin` runtime package.
If the pinned `codex-cli-bin` runtime is not already installed, the bootstrap
If the pinned `openai-codex-cli-bin` runtime is not already installed, the bootstrap
will download the matching GitHub release artifact, stage a temporary local
`codex-cli-bin` package, install it into your active interpreter, and clean up
the temporary files afterward.
`openai-codex-cli-bin` package, install it into your active interpreter, and
clean up the temporary files afterward.
Current pinned runtime version: `0.116.0-alpha.1`
@@ -43,8 +43,8 @@ python examples/<example-folder>/async.py
The examples bootstrap local imports from `sdk/python/src` automatically, so no
SDK wheel install is required. You only need the Python dependencies for your
active interpreter and an installed `codex-cli-bin` runtime package (either
already present or automatically provisioned by the bootstrap).
active interpreter and an installed `openai-codex-cli-bin` runtime package
(either already present or automatically provisioned by the bootstrap).
## Recommended first run

View File

@@ -3,13 +3,13 @@ requires = ["hatchling>=1.24.0"]
build-backend = "hatchling.build"
[project]
name = "codex-app-server-sdk"
name = "openai-codex"
version = "0.2.0"
description = "Python SDK for Codex app-server v2"
readme = "README.md"
requires-python = ">=3.10"
license = { text = "Apache-2.0" }
authors = [{ name = "OpenClaw Assistant" }]
authors = [{ name = "OpenAI" }]
keywords = ["codex", "json-rpc", "sdk", "llm", "app-server"]
classifiers = [
"Development Status :: 4 - Beta",

View File

@@ -146,6 +146,7 @@ class Codex:
sandbox: SandboxMode | None = None,
service_name: str | None = None,
service_tier: ServiceTier | None = None,
session_start_source: ThreadStartSource | None = None,
) -> Thread:
params = ThreadStartParams(
approval_policy=approval_policy,
@@ -161,6 +162,7 @@ class Codex:
sandbox=sandbox,
service_name=service_name,
service_tier=service_tier,
session_start_source=session_start_source,
)
started = self._client.thread_start(params)
return Thread(self._client, started.thread.id)
@@ -336,6 +338,7 @@ class AsyncCodex:
sandbox: SandboxMode | None = None,
service_name: str | None = None,
service_tier: ServiceTier | None = None,
session_start_source: ThreadStartSource | None = None,
) -> AsyncThread:
await self._ensure_initialized()
params = ThreadStartParams(
@@ -352,6 +355,7 @@ class AsyncCodex:
sandbox=sandbox,
service_name=service_name,
service_tier=service_tier,
session_start_source=session_start_source,
)
started = await self._client.thread_start(params)
return AsyncThread(self, started.thread.id)

View File

@@ -44,6 +44,7 @@ from .v2_all import ThreadRealtimeClosedNotification
from .v2_all import ThreadRealtimeErrorNotification
from .v2_all import ThreadRealtimeItemAddedNotification
from .v2_all import ThreadRealtimeOutputAudioDeltaNotification
from .v2_all import ThreadRealtimeSdpNotification
from .v2_all import ThreadRealtimeStartedNotification
from .v2_all import ThreadRealtimeTranscriptUpdatedNotification
from .v2_all import ThreadStartedNotification
@@ -97,6 +98,7 @@ NOTIFICATION_MODELS: dict[str, type[BaseModel]] = {
"thread/realtime/error": ThreadRealtimeErrorNotification,
"thread/realtime/itemAdded": ThreadRealtimeItemAddedNotification,
"thread/realtime/outputAudio/delta": ThreadRealtimeOutputAudioDeltaNotification,
"thread/realtime/sdp": ThreadRealtimeSdpNotification,
"thread/realtime/started": ThreadRealtimeStartedNotification,
"thread/realtime/transcriptUpdated": ThreadRealtimeTranscriptUpdatedNotification,
"thread/started": ThreadStartedNotification,

View File

@@ -211,6 +211,18 @@ class AuthMode(Enum):
chatgpt_auth_tokens = "chatgptAuthTokens"
class AutoReviewDecisionSource(RootModel[Literal["agent"]]):
model_config = ConfigDict(
populate_by_name=True,
)
root: Annotated[
Literal["agent"],
Field(
description="[UNSTABLE] Source that produced a terminal guardian approval review decision."
),
]
class ByteRange(BaseModel):
model_config = ConfigDict(
populate_by_name=True,
@@ -832,6 +844,7 @@ class FeedbackUploadParams(BaseModel):
extra_log_files: Annotated[list[str] | None, Field(alias="extraLogFiles")] = None
include_logs: Annotated[bool, Field(alias="includeLogs")]
reason: str | None = None
tags: dict[str, Any] | None = None
thread_id: Annotated[str | None, Field(alias="threadId")] = None
@@ -870,7 +883,10 @@ class FsChangedNotification(BaseModel):
]
watch_id: Annotated[
str,
Field(alias="watchId", description="Watch identifier returned by `fs/watch`."),
Field(
alias="watchId",
description="Watch identifier previously provided to `fs/watch`.",
),
]
@@ -1054,7 +1070,10 @@ class FsUnwatchParams(BaseModel):
)
watch_id: Annotated[
str,
Field(alias="watchId", description="Watch identifier returned by `fs/watch`."),
Field(
alias="watchId",
description="Watch identifier previously provided to `fs/watch`.",
),
]
@@ -1072,6 +1091,13 @@ class FsWatchParams(BaseModel):
path: Annotated[
AbsolutePathBuf, Field(description="Absolute file or directory path to watch.")
]
watch_id: Annotated[
str,
Field(
alias="watchId",
description="Connection-scoped watch identifier used for `fs/unwatch` and `fs/changed`.",
),
]
class FsWatchResponse(BaseModel):
@@ -1082,13 +1108,6 @@ class FsWatchResponse(BaseModel):
AbsolutePathBuf,
Field(description="Canonicalized path associated with the watch."),
]
watch_id: Annotated[
str,
Field(
alias="watchId",
description="Connection-scoped watch identifier used for `fs/unwatch` and `fs/changed`.",
),
]
class FsWriteFileParams(BaseModel):
@@ -1199,17 +1218,57 @@ class GitInfo(BaseModel):
sha: str | None = None
class ApplyPatchGuardianApprovalReviewAction(BaseModel):
model_config = ConfigDict(
populate_by_name=True,
)
cwd: str
files: list[str]
type: Annotated[
Literal["applyPatch"], Field(title="ApplyPatchGuardianApprovalReviewActionType")
]
class McpToolCallGuardianApprovalReviewAction(BaseModel):
model_config = ConfigDict(
populate_by_name=True,
)
connector_id: Annotated[str | None, Field(alias="connectorId")] = None
connector_name: Annotated[str | None, Field(alias="connectorName")] = None
server: str
tool_name: Annotated[str, Field(alias="toolName")]
tool_title: Annotated[str | None, Field(alias="toolTitle")] = None
type: Annotated[
Literal["mcpToolCall"],
Field(title="McpToolCallGuardianApprovalReviewActionType"),
]
class GuardianApprovalReviewStatus(Enum):
in_progress = "inProgress"
approved = "approved"
denied = "denied"
timed_out = "timedOut"
aborted = "aborted"
class GuardianCommandSource(Enum):
shell = "shell"
unified_exec = "unifiedExec"
class GuardianRiskLevel(Enum):
low = "low"
medium = "medium"
high = "high"
critical = "critical"
class GuardianUserAuthorization(Enum):
unknown = "unknown"
low = "low"
medium = "medium"
high = "high"
class HookEventName(Enum):
@@ -1300,22 +1359,6 @@ class InputModality(Enum):
image = "image"
class ListMcpServerStatusParams(BaseModel):
model_config = ConfigDict(
populate_by_name=True,
)
cursor: Annotated[
str | None,
Field(description="Opaque pagination cursor returned by a previous call."),
] = None
limit: Annotated[
int | None,
Field(
description="Optional page size; defaults to a server-defined value.", ge=0
),
] = None
class ExecLocalShellAction(BaseModel):
model_config = ConfigDict(
populate_by_name=True,
@@ -1358,6 +1401,16 @@ class ChatgptLoginAccountParams(BaseModel):
]
class ChatgptDeviceCodeLoginAccountParams(BaseModel):
model_config = ConfigDict(
populate_by_name=True,
)
type: Annotated[
Literal["chatgptDeviceCode"],
Field(title="ChatgptDeviceCodev2::LoginAccountParamsType"),
]
class ChatgptAuthTokensLoginAccountParams(BaseModel):
model_config = ConfigDict(
populate_by_name=True,
@@ -1393,6 +1446,7 @@ class LoginAccountParams(
RootModel[
ApiKeyLoginAccountParams
| ChatgptLoginAccountParams
| ChatgptDeviceCodeLoginAccountParams
| ChatgptAuthTokensLoginAccountParams
]
):
@@ -1402,6 +1456,7 @@ class LoginAccountParams(
root: Annotated[
ApiKeyLoginAccountParams
| ChatgptLoginAccountParams
| ChatgptDeviceCodeLoginAccountParams
| ChatgptAuthTokensLoginAccountParams,
Field(title="LoginAccountParams"),
]
@@ -1433,6 +1488,31 @@ class ChatgptLoginAccountResponse(BaseModel):
]
class ChatgptDeviceCodeLoginAccountResponse(BaseModel):
model_config = ConfigDict(
populate_by_name=True,
)
login_id: Annotated[str, Field(alias="loginId")]
type: Annotated[
Literal["chatgptDeviceCode"],
Field(title="ChatgptDeviceCodev2::LoginAccountResponseType"),
]
user_code: Annotated[
str,
Field(
alias="userCode",
description="One-time code the user must enter after signing in.",
),
]
verification_url: Annotated[
str,
Field(
alias="verificationUrl",
description="URL the client should open in a browser to complete device code authorization.",
),
]
class ChatgptAuthTokensLoginAccountResponse(BaseModel):
model_config = ConfigDict(
populate_by_name=True,
@@ -1447,6 +1527,7 @@ class LoginAccountResponse(
RootModel[
ApiKeyLoginAccountResponse
| ChatgptLoginAccountResponse
| ChatgptDeviceCodeLoginAccountResponse
| ChatgptAuthTokensLoginAccountResponse
]
):
@@ -1456,6 +1537,7 @@ class LoginAccountResponse(
root: Annotated[
ApiKeyLoginAccountResponse
| ChatgptLoginAccountResponse
| ChatgptDeviceCodeLoginAccountResponse
| ChatgptAuthTokensLoginAccountResponse,
Field(title="LoginAccountResponse"),
]
@@ -1490,6 +1572,15 @@ class McpAuthStatus(Enum):
o_auth = "oAuth"
class McpResourceReadParams(BaseModel):
model_config = ConfigDict(
populate_by_name=True,
)
server: str
thread_id: Annotated[str, Field(alias="threadId")]
uri: str
class McpServerOauthLoginCompletedNotification(BaseModel):
model_config = ConfigDict(
populate_by_name=True,
@@ -1529,6 +1620,11 @@ class McpServerStartupState(Enum):
cancelled = "cancelled"
class McpServerStatusDetail(Enum):
full = "full"
tools_and_auth_only = "toolsAndAuthOnly"
class McpServerStatusUpdatedNotification(BaseModel):
model_config = ConfigDict(
populate_by_name=True,
@@ -1538,6 +1634,27 @@ class McpServerStatusUpdatedNotification(BaseModel):
status: McpServerStartupState
class McpServerToolCallParams(BaseModel):
model_config = ConfigDict(
populate_by_name=True,
)
field_meta: Annotated[Any | None, Field(alias="_meta")] = None
arguments: Any | None = None
server: str
thread_id: Annotated[str, Field(alias="threadId")]
tool: str
class McpServerToolCallResponse(BaseModel):
model_config = ConfigDict(
populate_by_name=True,
)
field_meta: Annotated[Any | None, Field(alias="_meta")] = None
content: list
is_error: Annotated[bool | None, Field(alias="isError")] = None
structured_content: Annotated[Any | None, Field(alias="structuredContent")] = None
class McpToolCallError(BaseModel):
model_config = ConfigDict(
populate_by_name=True,
@@ -1559,6 +1676,7 @@ class McpToolCallResult(BaseModel):
model_config = ConfigDict(
populate_by_name=True,
)
field_meta: Annotated[Any | None, Field(alias="_meta")] = None
content: list
structured_content: Annotated[Any | None, Field(alias="structuredContent")] = None
@@ -1658,28 +1776,84 @@ class NetworkAccess(Enum):
enabled = "enabled"
class NetworkApprovalProtocol(Enum):
http = "http"
https = "https"
socks5_tcp = "socks5Tcp"
socks5_udp = "socks5Udp"
class NetworkDomainPermission(Enum):
allow = "allow"
deny = "deny"
class NetworkRequirements(BaseModel):
model_config = ConfigDict(
populate_by_name=True,
)
allow_local_binding: Annotated[bool | None, Field(alias="allowLocalBinding")] = None
allow_unix_sockets: Annotated[list[str] | None, Field(alias="allowUnixSockets")] = (
None
)
allow_unix_sockets: Annotated[
list[str] | None,
Field(
alias="allowUnixSockets",
description="Legacy compatibility view derived from `unix_sockets`.",
),
] = None
allow_upstream_proxy: Annotated[bool | None, Field(alias="allowUpstreamProxy")] = (
None
)
allowed_domains: Annotated[list[str] | None, Field(alias="allowedDomains")] = None
allowed_domains: Annotated[
list[str] | None,
Field(
alias="allowedDomains",
description="Legacy compatibility view derived from `domains`.",
),
] = None
danger_full_access_denylist_only: Annotated[
bool | None, Field(alias="dangerFullAccessDenylistOnly")
] = None
dangerously_allow_all_unix_sockets: Annotated[
bool | None, Field(alias="dangerouslyAllowAllUnixSockets")
] = None
dangerously_allow_non_loopback_proxy: Annotated[
bool | None, Field(alias="dangerouslyAllowNonLoopbackProxy")
] = None
denied_domains: Annotated[list[str] | None, Field(alias="deniedDomains")] = None
denied_domains: Annotated[
list[str] | None,
Field(
alias="deniedDomains",
description="Legacy compatibility view derived from `domains`.",
),
] = None
domains: Annotated[
dict[str, Any] | None,
Field(
description="Canonical network permission map for `experimental_network`."
),
] = None
enabled: bool | None = None
http_port: Annotated[int | None, Field(alias="httpPort", ge=0)] = None
managed_allowed_domains_only: Annotated[
bool | None,
Field(
alias="managedAllowedDomainsOnly",
description="When true, only managed allowlist entries are respected while managed network enforcement is active.",
),
] = None
socks_port: Annotated[int | None, Field(alias="socksPort", ge=0)] = None
unix_sockets: Annotated[
dict[str, Any] | None,
Field(
alias="unixSockets",
description="Canonical unix socket permission map for `experimental_network`.",
),
] = None
class NetworkUnixSocketPermission(Enum):
allow = "allow"
none = "none"
class NonSteerableTurnKind(Enum):
@@ -1746,6 +1920,7 @@ class PlanType(Enum):
go = "go"
plus = "plus"
pro = "pro"
prolite = "prolite"
team = "team"
self_serve_business_usage_based = "self_serve_business_usage_based"
business = "business"
@@ -1935,6 +2110,38 @@ class RealtimeConversationVersion(Enum):
v2 = "v2"
class RealtimeVoice(Enum):
alloy = "alloy"
arbor = "arbor"
ash = "ash"
ballad = "ballad"
breeze = "breeze"
cedar = "cedar"
coral = "coral"
cove = "cove"
echo = "echo"
ember = "ember"
juniper = "juniper"
maple = "maple"
marin = "marin"
sage = "sage"
shimmer = "shimmer"
sol = "sol"
spruce = "spruce"
vale = "vale"
verse = "verse"
class RealtimeVoicesList(BaseModel):
model_config = ConfigDict(
populate_by_name=True,
)
default_v1: Annotated[RealtimeVoice, Field(alias="defaultV1")]
default_v2: Annotated[RealtimeVoice, Field(alias="defaultV2")]
v1: list[RealtimeVoice]
v2: list[RealtimeVoice]
class ReasoningEffort(Enum):
none = "none"
minimal = "minimal"
@@ -2078,6 +2285,38 @@ class Resource(BaseModel):
uri: str
class ResourceContent1(BaseModel):
model_config = ConfigDict(
populate_by_name=True,
)
field_meta: Annotated[Any | None, Field(alias="_meta")] = None
mime_type: Annotated[str | None, Field(alias="mimeType")] = None
text: str
uri: Annotated[str, Field(description="The URI of this resource.")]
class ResourceContent2(BaseModel):
model_config = ConfigDict(
populate_by_name=True,
)
field_meta: Annotated[Any | None, Field(alias="_meta")] = None
blob: str
mime_type: Annotated[str | None, Field(alias="mimeType")] = None
uri: Annotated[str, Field(description="The URI of this resource.")]
class ResourceContent(RootModel[ResourceContent1 | ResourceContent2]):
model_config = ConfigDict(
populate_by_name=True,
)
root: Annotated[
ResourceContent1 | ResourceContent2,
Field(
description="Contents returned when reading a resource from an MCP server."
),
]
class ResourceTemplate(BaseModel):
model_config = ConfigDict(
populate_by_name=True,
@@ -3222,6 +3461,52 @@ class ThreadRealtimeOutputAudioDeltaNotification(BaseModel):
thread_id: Annotated[str, Field(alias="threadId")]
class ThreadRealtimeSdpNotification(BaseModel):
model_config = ConfigDict(
populate_by_name=True,
)
sdp: str
thread_id: Annotated[str, Field(alias="threadId")]
class WebsocketThreadRealtimeStartTransport(BaseModel):
model_config = ConfigDict(
populate_by_name=True,
)
type: Annotated[
Literal["websocket"], Field(title="WebsocketThreadRealtimeStartTransportType")
]
class WebrtcThreadRealtimeStartTransport(BaseModel):
model_config = ConfigDict(
populate_by_name=True,
)
sdp: Annotated[
str,
Field(
description="SDP offer generated by a WebRTC RTCPeerConnection after configuring audio and the realtime events data channel."
),
]
type: Annotated[
Literal["webrtc"], Field(title="WebrtcThreadRealtimeStartTransportType")
]
class ThreadRealtimeStartTransport(
RootModel[
WebsocketThreadRealtimeStartTransport | WebrtcThreadRealtimeStartTransport
]
):
model_config = ConfigDict(
populate_by_name=True,
)
root: Annotated[
WebsocketThreadRealtimeStartTransport | WebrtcThreadRealtimeStartTransport,
Field(description="EXPERIMENTAL - transport used by thread realtime."),
]
class ThreadRealtimeStartedNotification(BaseModel):
model_config = ConfigDict(
populate_by_name=True,
@@ -3339,33 +3624,9 @@ class ThreadSourceKind(Enum):
unknown = "unknown"
class ThreadStartParams(BaseModel):
model_config = ConfigDict(
populate_by_name=True,
)
approval_policy: Annotated[AskForApproval | None, Field(alias="approvalPolicy")] = (
None
)
approvals_reviewer: Annotated[
ApprovalsReviewer | None,
Field(
alias="approvalsReviewer",
description="Override where approval requests are routed for review on this thread and subsequent turns.",
),
] = None
base_instructions: Annotated[str | None, Field(alias="baseInstructions")] = None
config: dict[str, Any] | None = None
cwd: str | None = None
developer_instructions: Annotated[
str | None, Field(alias="developerInstructions")
] = None
ephemeral: bool | None = None
model: str | None = None
model_provider: Annotated[str | None, Field(alias="modelProvider")] = None
personality: Personality | None = None
sandbox: SandboxMode | None = None
service_name: Annotated[str | None, Field(alias="serviceName")] = None
service_tier: Annotated[ServiceTier | None, Field(alias="serviceTier")] = None
class ThreadStartSource(Enum):
startup = "startup"
clear = "clear"
class NotLoadedThreadStatus(BaseModel):
@@ -3795,15 +4056,6 @@ class InitializeRequest(BaseModel):
params: InitializeParams
class ThreadStartRequest(BaseModel):
model_config = ConfigDict(
populate_by_name=True,
)
id: RequestId
method: Annotated[Literal["thread/start"], Field(title="Thread/startRequestMethod")]
params: ThreadStartParams
class ThreadResumeRequest(BaseModel):
model_config = ConfigDict(
populate_by_name=True,
@@ -4158,16 +4410,27 @@ class ConfigMcpServerReloadRequest(BaseModel):
params: None = None
class McpServerStatusListRequest(BaseModel):
class McpServerResourceReadRequest(BaseModel):
model_config = ConfigDict(
populate_by_name=True,
)
id: RequestId
method: Annotated[
Literal["mcpServerStatus/list"],
Field(title="McpServerStatus/listRequestMethod"),
Literal["mcpServer/resource/read"],
Field(title="McpServer/resource/readRequestMethod"),
]
params: ListMcpServerStatusParams
params: McpResourceReadParams
class McpServerToolCallRequest(BaseModel):
model_config = ConfigDict(
populate_by_name=True,
)
id: RequestId
method: Annotated[
Literal["mcpServer/tool/call"], Field(title="McpServer/tool/callRequestMethod")
]
params: McpServerToolCallParams
class WindowsSandboxSetupStartRequest(BaseModel):
@@ -4738,8 +5001,70 @@ class GuardianApprovalReview(BaseModel):
)
rationale: str | None = None
risk_level: Annotated[GuardianRiskLevel | None, Field(alias="riskLevel")] = None
risk_score: Annotated[int | None, Field(alias="riskScore", ge=0)] = None
status: GuardianApprovalReviewStatus
user_authorization: Annotated[
GuardianUserAuthorization | None, Field(alias="userAuthorization")
] = None
class CommandGuardianApprovalReviewAction(BaseModel):
model_config = ConfigDict(
populate_by_name=True,
)
command: str
cwd: str
source: GuardianCommandSource
type: Annotated[
Literal["command"], Field(title="CommandGuardianApprovalReviewActionType")
]
class ExecveGuardianApprovalReviewAction(BaseModel):
model_config = ConfigDict(
populate_by_name=True,
)
argv: list[str]
cwd: str
program: str
source: GuardianCommandSource
type: Annotated[
Literal["execve"], Field(title="ExecveGuardianApprovalReviewActionType")
]
class NetworkAccessGuardianApprovalReviewAction(BaseModel):
model_config = ConfigDict(
populate_by_name=True,
)
host: str
port: Annotated[int, Field(ge=0)]
protocol: NetworkApprovalProtocol
target: str
type: Annotated[
Literal["networkAccess"],
Field(title="NetworkAccessGuardianApprovalReviewActionType"),
]
class GuardianApprovalReviewAction(
RootModel[
CommandGuardianApprovalReviewAction
| ExecveGuardianApprovalReviewAction
| ApplyPatchGuardianApprovalReviewAction
| NetworkAccessGuardianApprovalReviewAction
| McpToolCallGuardianApprovalReviewAction
]
):
model_config = ConfigDict(
populate_by_name=True,
)
root: (
CommandGuardianApprovalReviewAction
| ExecveGuardianApprovalReviewAction
| ApplyPatchGuardianApprovalReviewAction
| NetworkAccessGuardianApprovalReviewAction
| McpToolCallGuardianApprovalReviewAction
)
class HookOutputEntry(BaseModel):
@@ -4782,9 +5107,19 @@ class ItemGuardianApprovalReviewCompletedNotification(BaseModel):
model_config = ConfigDict(
populate_by_name=True,
)
action: Any | None = None
action: GuardianApprovalReviewAction
decision_source: Annotated[AutoReviewDecisionSource, Field(alias="decisionSource")]
review: GuardianApprovalReview
target_item_id: Annotated[str, Field(alias="targetItemId")]
review_id: Annotated[
str, Field(alias="reviewId", description="Stable identifier for this review.")
]
target_item_id: Annotated[
str | None,
Field(
alias="targetItemId",
description="Identifier for the reviewed item or tool call when one exists.\n\nIn most cases, one review maps to one target item. The exceptions are - execve reviews, where a single command may contain multiple execve calls to review (only possible when using the shell_zsh_fork feature) - network policy reviews, where there is no target item\n\nA network call is triggered by a CommandExecution item, so having a target_item_id set to the CommandExecution item would be misleading because the review is about the network call, not the command execution. Therefore, target_item_id is set to None for network policy reviews.",
),
] = None
thread_id: Annotated[str, Field(alias="threadId")]
turn_id: Annotated[str, Field(alias="turnId")]
@@ -4793,13 +5128,51 @@ class ItemGuardianApprovalReviewStartedNotification(BaseModel):
model_config = ConfigDict(
populate_by_name=True,
)
action: Any | None = None
action: GuardianApprovalReviewAction
review: GuardianApprovalReview
target_item_id: Annotated[str, Field(alias="targetItemId")]
review_id: Annotated[
str, Field(alias="reviewId", description="Stable identifier for this review.")
]
target_item_id: Annotated[
str | None,
Field(
alias="targetItemId",
description="Identifier for the reviewed item or tool call when one exists.\n\nIn most cases, one review maps to one target item. The exceptions are - execve reviews, where a single command may contain multiple execve calls to review (only possible when using the shell_zsh_fork feature) - network policy reviews, where there is no target item\n\nA network call is triggered by a CommandExecution item, so having a target_item_id set to the CommandExecution item would be misleading because the review is about the network call, not the command execution. Therefore, target_item_id is set to None for network policy reviews.",
),
] = None
thread_id: Annotated[str, Field(alias="threadId")]
turn_id: Annotated[str, Field(alias="turnId")]
class ListMcpServerStatusParams(BaseModel):
model_config = ConfigDict(
populate_by_name=True,
)
cursor: Annotated[
str | None,
Field(description="Opaque pagination cursor returned by a previous call."),
] = None
detail: Annotated[
McpServerStatusDetail | None,
Field(
description="Controls how much MCP inventory data to fetch for each server. Defaults to `Full` when omitted."
),
] = None
limit: Annotated[
int | None,
Field(
description="Optional page size; defaults to a server-defined value.", ge=0
),
] = None
class McpResourceReadResponse(BaseModel):
model_config = ConfigDict(
populate_by_name=True,
)
contents: list[ResourceContent]
class McpServerStatus(BaseModel):
model_config = ConfigDict(
populate_by_name=True,
@@ -4825,6 +5198,9 @@ class Model(BaseModel):
model_config = ConfigDict(
populate_by_name=True,
)
additional_speed_tiers: Annotated[
list[str] | None, Field(alias="additionalSpeedTiers")
] = []
availability_nux: Annotated[
ModelAvailabilityNux | None, Field(alias="availabilityNux")
] = None
@@ -5142,6 +5518,17 @@ class ThreadRealtimeOutputAudioDeltaServerNotification(BaseModel):
params: ThreadRealtimeOutputAudioDeltaNotification
class ThreadRealtimeSdpServerNotification(BaseModel):
model_config = ConfigDict(
populate_by_name=True,
)
method: Annotated[
Literal["thread/realtime/sdp"],
Field(title="Thread/realtime/sdpNotificationMethod"),
]
params: ThreadRealtimeSdpNotification
class ThreadRealtimeErrorServerNotification(BaseModel):
model_config = ConfigDict(
populate_by_name=True,
@@ -5444,6 +5831,38 @@ class ThreadListParams(BaseModel):
] = None
class ThreadStartParams(BaseModel):
model_config = ConfigDict(
populate_by_name=True,
)
approval_policy: Annotated[AskForApproval | None, Field(alias="approvalPolicy")] = (
None
)
approvals_reviewer: Annotated[
ApprovalsReviewer | None,
Field(
alias="approvalsReviewer",
description="Override where approval requests are routed for review on this thread and subsequent turns.",
),
] = None
base_instructions: Annotated[str | None, Field(alias="baseInstructions")] = None
config: dict[str, Any] | None = None
cwd: str | None = None
developer_instructions: Annotated[
str | None, Field(alias="developerInstructions")
] = None
ephemeral: bool | None = None
model: str | None = None
model_provider: Annotated[str | None, Field(alias="modelProvider")] = None
personality: Personality | None = None
sandbox: SandboxMode | None = None
service_name: Annotated[str | None, Field(alias="serviceName")] = None
service_tier: Annotated[ServiceTier | None, Field(alias="serviceTier")] = None
session_start_source: Annotated[
ThreadStartSource | None, Field(alias="sessionStartSource")
] = None
class ThreadTokenUsage(BaseModel):
model_config = ConfigDict(
populate_by_name=True,
@@ -5660,6 +6079,15 @@ class AppsListResponse(BaseModel):
] = None
class ThreadStartRequest(BaseModel):
model_config = ConfigDict(
populate_by_name=True,
)
id: RequestId
method: Annotated[Literal["thread/start"], Field(title="Thread/startRequestMethod")]
params: ThreadStartParams
class ThreadListRequest(BaseModel):
model_config = ConfigDict(
populate_by_name=True,
@@ -5696,6 +6124,18 @@ class ReviewStartRequest(BaseModel):
params: ReviewStartParams
class McpServerStatusListRequest(BaseModel):
model_config = ConfigDict(
populate_by_name=True,
)
id: RequestId
method: Annotated[
Literal["mcpServerStatus/list"],
Field(title="McpServerStatus/listRequestMethod"),
]
params: ListMcpServerStatusParams
class CommandExecRequest(BaseModel):
model_config = ConfigDict(
populate_by_name=True,
@@ -6074,6 +6514,20 @@ class Turn(BaseModel):
model_config = ConfigDict(
populate_by_name=True,
)
completed_at: Annotated[
int | None,
Field(
alias="completedAt",
description="Unix timestamp (in seconds) when the turn completed.",
),
] = None
duration_ms: Annotated[
int | None,
Field(
alias="durationMs",
description="Duration between turn start and completion in milliseconds, if known.",
),
] = None
error: Annotated[
TurnError | None,
Field(description="Only populated when the Turn's status is failed."),
@@ -6085,6 +6539,13 @@ class Turn(BaseModel):
description="Only populated on a `thread/resume` or `thread/fork` response. For all other responses and notifications returning a Turn, the items field will be an empty list."
),
]
started_at: Annotated[
int | None,
Field(
alias="startedAt",
description="Unix timestamp (in seconds) when the turn started.",
),
] = None
status: TurnStatus
@@ -6177,6 +6638,8 @@ class ClientRequest(
| McpServerOauthLoginRequest
| ConfigMcpServerReloadRequest
| McpServerStatusListRequest
| McpServerResourceReadRequest
| McpServerToolCallRequest
| WindowsSandboxSetupStartRequest
| AccountLoginStartRequest
| AccountLoginCancelRequest
@@ -6242,6 +6705,8 @@ class ClientRequest(
| McpServerOauthLoginRequest
| ConfigMcpServerReloadRequest
| McpServerStatusListRequest
| McpServerResourceReadRequest
| McpServerToolCallRequest
| WindowsSandboxSetupStartRequest
| AccountLoginStartRequest
| AccountLoginCancelRequest
@@ -6392,6 +6857,13 @@ class Thread(BaseModel):
description="Whether the thread is ephemeral and should not be materialized on disk."
),
]
forked_from_id: Annotated[
str | None,
Field(
alias="forkedFromId",
description="Source thread id when this thread was created by forking another thread.",
),
] = None
git_info: Annotated[
GitInfo | None,
Field(
@@ -6456,6 +6928,13 @@ class ThreadForkResponse(BaseModel):
),
]
cwd: str
instruction_sources: Annotated[
list[str] | None,
Field(
alias="instructionSources",
description="Instruction source files currently loaded for this thread.",
),
] = []
model: str
model_provider: Annotated[str, Field(alias="modelProvider")]
reasoning_effort: Annotated[
@@ -6507,6 +6986,13 @@ class ThreadResumeResponse(BaseModel):
),
]
cwd: str
instruction_sources: Annotated[
list[str] | None,
Field(
alias="instructionSources",
description="Instruction source files currently loaded for this thread.",
),
] = []
model: str
model_provider: Annotated[str, Field(alias="modelProvider")]
reasoning_effort: Annotated[
@@ -6542,6 +7028,13 @@ class ThreadStartResponse(BaseModel):
),
]
cwd: str
instruction_sources: Annotated[
list[str] | None,
Field(
alias="instructionSources",
description="Instruction source files currently loaded for this thread.",
),
] = []
model: str
model_provider: Annotated[str, Field(alias="modelProvider")]
reasoning_effort: Annotated[
@@ -6624,6 +7117,7 @@ class ServerNotification(
| ThreadRealtimeItemAddedServerNotification
| ThreadRealtimeTranscriptUpdatedServerNotification
| ThreadRealtimeOutputAudioDeltaServerNotification
| ThreadRealtimeSdpServerNotification
| ThreadRealtimeErrorServerNotification
| ThreadRealtimeClosedServerNotification
| WindowsWorldWritableWarningServerNotification
@@ -6681,6 +7175,7 @@ class ServerNotification(
| ThreadRealtimeItemAddedServerNotification
| ThreadRealtimeTranscriptUpdatedServerNotification
| ThreadRealtimeOutputAudioDeltaServerNotification
| ThreadRealtimeSdpServerNotification
| ThreadRealtimeErrorServerNotification
| ThreadRealtimeClosedServerNotification
| WindowsWorldWritableWarningServerNotification

View File

@@ -56,6 +56,7 @@ def test_generated_public_signatures_are_snake_case_and_typed() -> None:
"sandbox",
"service_name",
"service_tier",
"session_start_source",
],
Codex.thread_list: [
"archived",
@@ -131,6 +132,7 @@ def test_generated_public_signatures_are_snake_case_and_typed() -> None:
"sandbox",
"service_name",
"service_tier",
"session_start_source",
],
AsyncCodex.thread_list: [
"archived",