mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
[codex] Add independent beta release for the Python SDK (#24828)
## Why `openai-codex` needs a beta release lifecycle without requiring beta releases of its pinned runtime package. Previously, SDK staging rewrote its runtime dependency to the SDK version, which made an SDK-only beta impossible. ## What changed - Set the initial SDK beta version to `0.1.0b1` and pin it to published stable `openai-codex-cli-bin==0.132.0`. - Decoupled SDK release staging from runtime versioning so it preserves the reviewed exact runtime pin. - Added a `python-v*` tag workflow that builds and publishes only `openai-codex` through PyPI trusted publishing. - Removed the Beta classifier from runtime package metadata for future runtime publications. - Regenerated protocol-derived SDK models from the selected stable runtime package. `0.132.0` is the newest stable runtime admitted by the checked-in dependency date fence and retains the Linux wheel family currently used by SDK CI. ## Release setup Before pushing `python-v0.1.0b1`, configure PyPI trusted publishing for the `openai-codex` project with workflow `python-sdk-release.yml`, environment `pypi`, and job `publish-python-sdk`. ## Validation - `uv run --frozen --extra dev ruff check src/openai_codex scripts examples tests` - Parsed `.github/workflows/python-sdk-release.yml` with PyYAML. - Built staged release artifacts locally: `openai_codex-0.1.0b1-py3-none-any.whl` and `openai_codex-0.1.0b1.tar.gz`. - Verified wheel metadata pins `openai-codex-cli-bin==0.132.0`. - Tests are deferred to online CI for this PR.
This commit is contained in:
committed by
GitHub
Unverified
parent
304d15cab0
commit
4d0c4cd058
@@ -16,8 +16,8 @@ uv sync
|
||||
source .venv/bin/activate
|
||||
```
|
||||
|
||||
Published SDK builds pin an exact `openai-codex-cli-bin` runtime dependency
|
||||
with the same version as the SDK. Pass `CodexConfig(codex_bin=...)` only
|
||||
Published SDK builds pin an exact compatible `openai-codex-cli-bin` runtime
|
||||
dependency. Pass `CodexConfig(codex_bin=...)` only
|
||||
when you intentionally want to run against a specific local app-server binary.
|
||||
|
||||
## Quickstart
|
||||
@@ -111,7 +111,7 @@ python examples/01_quickstart_constructor/async.py
|
||||
|
||||
Published SDK builds are pinned to an exact `openai-codex-cli-bin` package
|
||||
version, and that runtime package carries the platform-specific binary for the
|
||||
target wheel. The SDK package version and runtime package version must match.
|
||||
target wheel. SDK beta releases are versioned independently of runtime releases.
|
||||
|
||||
## Compatibility and versioning
|
||||
|
||||
@@ -119,7 +119,7 @@ target wheel. The SDK package version and runtime package version must match.
|
||||
- Runtime package: `openai-codex-cli-bin`
|
||||
- Python: `>=3.10`
|
||||
- Target protocol: Codex `app-server` JSON-RPC v2
|
||||
- Versioning rule: the SDK package version is the underlying Codex runtime version
|
||||
- Versioning rule: SDK releases pin one exact compatible Codex runtime version
|
||||
|
||||
## Notes
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
||||
|
||||
[project]
|
||||
name = "openai-codex"
|
||||
version = "0.131.0a4"
|
||||
version = "0.1.0b1"
|
||||
description = "Python SDK for Codex app-server v2"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.10"
|
||||
@@ -22,7 +22,7 @@ classifiers = [
|
||||
"Programming Language :: Python :: 3.13",
|
||||
"Topic :: Software Development :: Libraries :: Python Modules",
|
||||
]
|
||||
dependencies = ["pydantic>=2.12", "openai-codex-cli-bin==0.131.0a4"]
|
||||
dependencies = ["pydantic>=2.12", "openai-codex-cli-bin==0.132.0"]
|
||||
|
||||
[project.urls]
|
||||
Homepage = "https://github.com/openai/codex"
|
||||
@@ -86,10 +86,10 @@ combine-as-imports = true
|
||||
|
||||
[tool.uv]
|
||||
exclude-newer = "7 days"
|
||||
exclude-newer-package = { openai-codex-cli-bin = "2026-05-10T00:00:00Z" }
|
||||
exclude-newer-package = { openai-codex-cli-bin = "2026-05-20T21:00:00Z" }
|
||||
index-strategy = "first-index"
|
||||
|
||||
[tool.uv.pip]
|
||||
exclude-newer = "7 days"
|
||||
exclude-newer-package = { openai-codex-cli-bin = "2026-05-10T00:00:00Z" }
|
||||
exclude-newer-package = { openai-codex-cli-bin = "2026-05-20T21:00:00Z" }
|
||||
index-strategy = "first-index"
|
||||
|
||||
@@ -216,25 +216,8 @@ def _rewrite_project_name(pyproject_text: str, name: str) -> str:
|
||||
return updated
|
||||
|
||||
|
||||
def _rewrite_sdk_runtime_dependency(pyproject_text: str, runtime_version: str) -> str:
|
||||
match = re.search(r"^dependencies = \[(.*?)\]$", pyproject_text, flags=re.MULTILINE)
|
||||
if match is None:
|
||||
raise RuntimeError("Could not find dependencies array in sdk/python/pyproject.toml")
|
||||
|
||||
raw_items = [item.strip() for item in match.group(1).split(",") if item.strip()]
|
||||
raw_items = [
|
||||
item
|
||||
for item in raw_items
|
||||
if RUNTIME_DISTRIBUTION_NAME.removeprefix("openai-") not in item
|
||||
and RUNTIME_DISTRIBUTION_NAME not in item
|
||||
]
|
||||
raw_items.append(f'"{RUNTIME_DISTRIBUTION_NAME}=={runtime_version}"')
|
||||
replacement = "dependencies = [\n " + ",\n ".join(raw_items) + ",\n]"
|
||||
return pyproject_text[: match.start()] + replacement + pyproject_text[match.end() :]
|
||||
|
||||
|
||||
def stage_python_sdk_package(staging_dir: Path, codex_version: str) -> Path:
|
||||
package_version = normalize_codex_version(codex_version)
|
||||
def stage_python_sdk_package(staging_dir: Path, sdk_version: str) -> Path:
|
||||
package_version = normalize_codex_version(sdk_version)
|
||||
_copy_package_tree(sdk_root(), staging_dir)
|
||||
sdk_bin_dir = staging_dir / "src" / "openai_codex" / "bin"
|
||||
if sdk_bin_dir.exists():
|
||||
@@ -244,7 +227,6 @@ def stage_python_sdk_package(staging_dir: Path, codex_version: str) -> Path:
|
||||
pyproject_text = pyproject_path.read_text()
|
||||
pyproject_text = _rewrite_project_name(pyproject_text, SDK_DISTRIBUTION_NAME)
|
||||
pyproject_text = _rewrite_project_version(pyproject_text, package_version)
|
||||
pyproject_text = _rewrite_sdk_runtime_dependency(pyproject_text, package_version)
|
||||
pyproject_path.write_text(pyproject_text)
|
||||
return staging_dir
|
||||
|
||||
@@ -1229,28 +1211,20 @@ def build_parser() -> argparse.ArgumentParser:
|
||||
|
||||
stage_sdk_parser = subparsers.add_parser(
|
||||
"stage-sdk",
|
||||
help="Stage a releasable SDK package pinned to a runtime version",
|
||||
help="Stage a releasable SDK package while preserving its reviewed runtime pin",
|
||||
)
|
||||
stage_sdk_parser.add_argument(
|
||||
"staging_dir",
|
||||
type=Path,
|
||||
help="Output directory for the staged SDK package",
|
||||
)
|
||||
stage_sdk_parser.add_argument(
|
||||
"--codex-version",
|
||||
help=(
|
||||
"Codex release version to write into the staged SDK package and exact "
|
||||
f"{RUNTIME_DISTRIBUTION_NAME} dependency. Accepts PEP 440 versions "
|
||||
"or release tags such as rust-v0.116.0-alpha.1."
|
||||
),
|
||||
)
|
||||
stage_sdk_parser.add_argument(
|
||||
"--runtime-version",
|
||||
help=argparse.SUPPRESS,
|
||||
)
|
||||
stage_sdk_parser.add_argument(
|
||||
"--sdk-version",
|
||||
help=argparse.SUPPRESS,
|
||||
required=True,
|
||||
help=(
|
||||
"Python SDK release version to write into the staged package. "
|
||||
"Accepts PEP 440 versions such as 0.1.0b1."
|
||||
),
|
||||
)
|
||||
|
||||
stage_runtime_parser = subparsers.add_parser(
|
||||
@@ -1269,15 +1243,12 @@ def build_parser() -> argparse.ArgumentParser:
|
||||
)
|
||||
stage_runtime_parser.add_argument(
|
||||
"--codex-version",
|
||||
required=True,
|
||||
help=(
|
||||
"Codex release version to write into the staged runtime package. "
|
||||
"Accepts PEP 440 versions or release tags such as rust-v0.116.0-alpha.1."
|
||||
),
|
||||
)
|
||||
stage_runtime_parser.add_argument(
|
||||
"--runtime-version",
|
||||
help=argparse.SUPPRESS,
|
||||
)
|
||||
stage_runtime_parser.add_argument(
|
||||
"--platform-tag",
|
||||
help=(
|
||||
@@ -1301,40 +1272,19 @@ def default_cli_ops() -> CliOps:
|
||||
)
|
||||
|
||||
|
||||
def _resolve_codex_version(args: argparse.Namespace) -> str:
|
||||
versions = [
|
||||
value
|
||||
for value in (
|
||||
getattr(args, "codex_version", None),
|
||||
getattr(args, "runtime_version", None),
|
||||
getattr(args, "sdk_version", None),
|
||||
)
|
||||
if value is not None
|
||||
]
|
||||
if not versions:
|
||||
raise RuntimeError("Pass --codex-version to stage Python release artifacts")
|
||||
|
||||
normalized_versions = [normalize_codex_version(version) for version in versions]
|
||||
if len(set(normalized_versions)) != 1:
|
||||
raise RuntimeError("SDK and runtime package versions must match; pass one --codex-version")
|
||||
return normalized_versions[0]
|
||||
|
||||
|
||||
def run_command(args: argparse.Namespace, ops: CliOps) -> None:
|
||||
if args.command == "generate-types":
|
||||
ops.generate_types()
|
||||
elif args.command == "stage-sdk":
|
||||
codex_version = _resolve_codex_version(args)
|
||||
ops.generate_types()
|
||||
ops.stage_python_sdk_package(
|
||||
args.staging_dir,
|
||||
codex_version,
|
||||
normalize_codex_version(args.sdk_version),
|
||||
)
|
||||
elif args.command == "stage-runtime":
|
||||
codex_version = _resolve_codex_version(args)
|
||||
ops.stage_python_runtime_package(
|
||||
args.staging_dir,
|
||||
codex_version,
|
||||
normalize_codex_version(args.codex_version),
|
||||
args.package_archive.resolve(),
|
||||
args.platform_tag,
|
||||
)
|
||||
|
||||
@@ -49,26 +49,24 @@ class AccountLoginCompletedNotification(BaseModel):
|
||||
success: bool
|
||||
|
||||
|
||||
class AdditionalWritableRootActivePermissionProfileModification(BaseModel):
|
||||
class ActivePermissionProfile(BaseModel):
|
||||
model_config = ConfigDict(
|
||||
populate_by_name=True,
|
||||
)
|
||||
path: AbsolutePathBuf
|
||||
type: Annotated[
|
||||
Literal["additionalWritableRoot"],
|
||||
Field(title="AdditionalWritableRootActivePermissionProfileModificationType"),
|
||||
extends: Annotated[
|
||||
str | None,
|
||||
Field(
|
||||
description="Parent profile identifier once permissions profiles support inheritance. This is currently always `null`."
|
||||
),
|
||||
] = None
|
||||
id: Annotated[
|
||||
str,
|
||||
Field(
|
||||
description="Identifier from `default_permissions` or the implicit built-in default, such as `:workspace` or a user-defined `[permissions.<id>]` profile."
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
class ActivePermissionProfileModification(
|
||||
RootModel[AdditionalWritableRootActivePermissionProfileModification]
|
||||
):
|
||||
model_config = ConfigDict(
|
||||
populate_by_name=True,
|
||||
)
|
||||
root: AdditionalWritableRootActivePermissionProfileModification
|
||||
|
||||
|
||||
class AddCreditsNudgeCreditType(Enum):
|
||||
credits = "credits"
|
||||
usage_limit = "usage_limit"
|
||||
@@ -597,6 +595,12 @@ class UserConfigLayerSource(BaseModel):
|
||||
description="This is the path to the user's config.toml file, though it is not guaranteed to exist."
|
||||
),
|
||||
]
|
||||
profile: Annotated[
|
||||
str | None,
|
||||
Field(
|
||||
description="Name of the selected profile-v2 config layered on top of the base user config, when this layer represents one."
|
||||
),
|
||||
] = None
|
||||
type: Annotated[Literal["user"], Field(title="UserConfigLayerSourceType")]
|
||||
|
||||
|
||||
@@ -680,6 +684,7 @@ class CommandConfiguredHookHandler(BaseModel):
|
||||
)
|
||||
async_: Annotated[bool, Field(alias="async")]
|
||||
command: str
|
||||
command_windows: Annotated[str | None, Field(alias="commandWindows")] = None
|
||||
status_message: Annotated[str | None, Field(alias="statusMessage")] = None
|
||||
timeout_sec: Annotated[int | None, Field(alias="timeoutSec", ge=0)] = None
|
||||
type: Annotated[Literal["command"], Field(title="CommandConfiguredHookHandlerType")]
|
||||
@@ -842,6 +847,13 @@ class ExperimentalFeatureListParams(BaseModel):
|
||||
int | None,
|
||||
Field(description="Optional page size; defaults to a reasonable server-side value.", ge=0),
|
||||
] = None
|
||||
thread_id: Annotated[
|
||||
str | None,
|
||||
Field(
|
||||
alias="threadId",
|
||||
description="Optional loaded thread id. Pass this when showing feature state for an existing thread so enablement is computed from that thread's refreshed config, including project-local config for the thread's cwd.",
|
||||
),
|
||||
] = None
|
||||
|
||||
|
||||
class ExperimentalFeatureStage(Enum):
|
||||
@@ -1014,6 +1026,18 @@ class FileSystemSpecialPath(
|
||||
)
|
||||
|
||||
|
||||
class ForcedChatgptWorkspaceIds(RootModel[str | list[str]]):
|
||||
model_config = ConfigDict(
|
||||
populate_by_name=True,
|
||||
)
|
||||
root: Annotated[
|
||||
str | list[str],
|
||||
Field(
|
||||
description="Backward-compatible API shape for ChatGPT workspace login restrictions."
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
class ForcedLoginMethod(Enum):
|
||||
chatgpt = "chatgpt"
|
||||
api = "api"
|
||||
@@ -1482,8 +1506,6 @@ class HooksListParams(BaseModel):
|
||||
|
||||
|
||||
class ImageDetail(Enum):
|
||||
auto = "auto"
|
||||
low = "low"
|
||||
high = "high"
|
||||
original = "original"
|
||||
|
||||
@@ -2166,66 +2188,6 @@ class PatchChangeKind(
|
||||
root: AddPatchChangeKind | DeletePatchChangeKind | UpdatePatchChangeKind
|
||||
|
||||
|
||||
class DisabledPermissionProfile(BaseModel):
|
||||
model_config = ConfigDict(
|
||||
populate_by_name=True,
|
||||
)
|
||||
type: Annotated[Literal["disabled"], Field(title="DisabledPermissionProfileType")]
|
||||
|
||||
|
||||
class UnrestrictedPermissionProfileFileSystemPermissions(BaseModel):
|
||||
model_config = ConfigDict(
|
||||
populate_by_name=True,
|
||||
)
|
||||
type: Annotated[
|
||||
Literal["unrestricted"],
|
||||
Field(title="UnrestrictedPermissionProfileFileSystemPermissionsType"),
|
||||
]
|
||||
|
||||
|
||||
class AdditionalWritableRootPermissionProfileModificationParams(BaseModel):
|
||||
model_config = ConfigDict(
|
||||
populate_by_name=True,
|
||||
)
|
||||
path: AbsolutePathBuf
|
||||
type: Annotated[
|
||||
Literal["additionalWritableRoot"],
|
||||
Field(title="AdditionalWritableRootPermissionProfileModificationParamsType"),
|
||||
]
|
||||
|
||||
|
||||
class PermissionProfileModificationParams(
|
||||
RootModel[AdditionalWritableRootPermissionProfileModificationParams]
|
||||
):
|
||||
model_config = ConfigDict(
|
||||
populate_by_name=True,
|
||||
)
|
||||
root: AdditionalWritableRootPermissionProfileModificationParams
|
||||
|
||||
|
||||
class PermissionProfileNetworkPermissions(BaseModel):
|
||||
model_config = ConfigDict(
|
||||
populate_by_name=True,
|
||||
)
|
||||
enabled: bool
|
||||
|
||||
|
||||
class ProfilePermissionProfileSelectionParams(BaseModel):
|
||||
model_config = ConfigDict(
|
||||
populate_by_name=True,
|
||||
)
|
||||
id: str
|
||||
modifications: list[PermissionProfileModificationParams] | None = None
|
||||
type: Annotated[Literal["profile"], Field(title="ProfilePermissionProfileSelectionParamsType")]
|
||||
|
||||
|
||||
class PermissionProfileSelectionParams(RootModel[ProfilePermissionProfileSelectionParams]):
|
||||
model_config = ConfigDict(
|
||||
populate_by_name=True,
|
||||
)
|
||||
root: ProfilePermissionProfileSelectionParams
|
||||
|
||||
|
||||
class Personality(Enum):
|
||||
none = "none"
|
||||
friendly = "friendly"
|
||||
@@ -2298,6 +2260,23 @@ class PluginInstallResponse(BaseModel):
|
||||
auth_policy: Annotated[PluginAuthPolicy, Field(alias="authPolicy")]
|
||||
|
||||
|
||||
class PluginInstalledParams(BaseModel):
|
||||
model_config = ConfigDict(
|
||||
populate_by_name=True,
|
||||
)
|
||||
cwds: Annotated[
|
||||
list[AbsolutePathBuf] | None,
|
||||
Field(description="Optional working directories used to discover repo marketplaces."),
|
||||
] = None
|
||||
install_suggestion_plugin_names: Annotated[
|
||||
list[str] | None,
|
||||
Field(
|
||||
alias="installSuggestionPluginNames",
|
||||
description="Additional uninstalled plugin names that should be returned when present locally. This is used by mention surfaces that intentionally expose install entrypoints.",
|
||||
),
|
||||
] = None
|
||||
|
||||
|
||||
class PluginInterface(BaseModel):
|
||||
model_config = ConfigDict(
|
||||
populate_by_name=True,
|
||||
@@ -2385,6 +2364,26 @@ class PluginReadParams(BaseModel):
|
||||
remote_marketplace_name: Annotated[str | None, Field(alias="remoteMarketplaceName")] = None
|
||||
|
||||
|
||||
class PluginShareCheckoutParams(BaseModel):
|
||||
model_config = ConfigDict(
|
||||
populate_by_name=True,
|
||||
)
|
||||
remote_plugin_id: Annotated[str, Field(alias="remotePluginId")]
|
||||
|
||||
|
||||
class PluginShareCheckoutResponse(BaseModel):
|
||||
model_config = ConfigDict(
|
||||
populate_by_name=True,
|
||||
)
|
||||
marketplace_name: Annotated[str, Field(alias="marketplaceName")]
|
||||
marketplace_path: Annotated[AbsolutePathBuf, Field(alias="marketplacePath")]
|
||||
plugin_id: Annotated[str, Field(alias="pluginId")]
|
||||
plugin_name: Annotated[str, Field(alias="pluginName")]
|
||||
plugin_path: Annotated[AbsolutePathBuf, Field(alias="pluginPath")]
|
||||
remote_plugin_id: Annotated[str, Field(alias="remotePluginId")]
|
||||
remote_version: Annotated[str | None, Field(alias="remoteVersion")] = None
|
||||
|
||||
|
||||
class PluginShareDeleteParams(BaseModel):
|
||||
model_config = ConfigDict(
|
||||
populate_by_name=True,
|
||||
@@ -2745,6 +2744,7 @@ class RemoteControlStatusChangedNotification(BaseModel):
|
||||
)
|
||||
environment_id: Annotated[str | None, Field(alias="environmentId")] = None
|
||||
installation_id: Annotated[str, Field(alias="installationId")]
|
||||
server_name: Annotated[str, Field(alias="serverName")]
|
||||
status: RemoteControlConnectionStatus
|
||||
|
||||
|
||||
@@ -2911,6 +2911,13 @@ class CompactionResponseItem(BaseModel):
|
||||
type: Annotated[Literal["compaction"], Field(title="CompactionResponseItemType")]
|
||||
|
||||
|
||||
class CompactionTriggerResponseItem(BaseModel):
|
||||
model_config = ConfigDict(
|
||||
populate_by_name=True,
|
||||
)
|
||||
type: Annotated[Literal["compaction_trigger"], Field(title="CompactionTriggerResponseItemType")]
|
||||
|
||||
|
||||
class ContextCompactionResponseItem(BaseModel):
|
||||
model_config = ConfigDict(
|
||||
populate_by_name=True,
|
||||
@@ -3627,6 +3634,8 @@ class ThreadGoalClearedNotification(BaseModel):
|
||||
class ThreadGoalStatus(Enum):
|
||||
active = "active"
|
||||
paused = "paused"
|
||||
blocked = "blocked"
|
||||
usage_limited = "usageLimited"
|
||||
budget_limited = "budgetLimited"
|
||||
complete = "complete"
|
||||
|
||||
@@ -4308,6 +4317,7 @@ class ImageUserInput(BaseModel):
|
||||
model_config = ConfigDict(
|
||||
populate_by_name=True,
|
||||
)
|
||||
detail: ImageDetail | None = None
|
||||
type: Annotated[Literal["image"], Field(title="ImageUserInputType")]
|
||||
url: str
|
||||
|
||||
@@ -4316,6 +4326,7 @@ class LocalImageUserInput(BaseModel):
|
||||
model_config = ConfigDict(
|
||||
populate_by_name=True,
|
||||
)
|
||||
detail: ImageDetail | None = None
|
||||
path: str
|
||||
type: Annotated[Literal["localImage"], Field(title="LocalImageUserInputType")]
|
||||
|
||||
@@ -4525,30 +4536,6 @@ class AccountUpdatedNotification(BaseModel):
|
||||
plan_type: Annotated[PlanType | None, Field(alias="planType")] = None
|
||||
|
||||
|
||||
class ActivePermissionProfile(BaseModel):
|
||||
model_config = ConfigDict(
|
||||
populate_by_name=True,
|
||||
)
|
||||
extends: Annotated[
|
||||
str | None,
|
||||
Field(
|
||||
description="Parent profile identifier once permissions profiles support inheritance. This is currently always `null`."
|
||||
),
|
||||
] = None
|
||||
id: Annotated[
|
||||
str,
|
||||
Field(
|
||||
description="Identifier from `default_permissions` or the implicit built-in default, such as `:workspace` or a user-defined `[permissions.<id>]` profile."
|
||||
),
|
||||
]
|
||||
modifications: Annotated[
|
||||
list[ActivePermissionProfileModification] | None,
|
||||
Field(
|
||||
description="Bounded user-requested modifications applied on top of the named profile, if any."
|
||||
),
|
||||
] = []
|
||||
|
||||
|
||||
class AppConfig(BaseModel):
|
||||
model_config = ConfigDict(
|
||||
populate_by_name=True,
|
||||
@@ -4790,6 +4777,15 @@ class PluginListRequest(BaseModel):
|
||||
params: PluginListParams
|
||||
|
||||
|
||||
class PluginInstalledRequest(BaseModel):
|
||||
model_config = ConfigDict(
|
||||
populate_by_name=True,
|
||||
)
|
||||
id: RequestId
|
||||
method: Annotated[Literal["plugin/installed"], Field(title="Plugin/installedRequestMethod")]
|
||||
params: PluginInstalledParams
|
||||
|
||||
|
||||
class PluginReadRequest(BaseModel):
|
||||
model_config = ConfigDict(
|
||||
populate_by_name=True,
|
||||
@@ -4817,6 +4813,17 @@ class PluginShareListRequest(BaseModel):
|
||||
params: PluginShareListParams
|
||||
|
||||
|
||||
class PluginShareCheckoutRequest(BaseModel):
|
||||
model_config = ConfigDict(
|
||||
populate_by_name=True,
|
||||
)
|
||||
id: RequestId
|
||||
method: Annotated[
|
||||
Literal["plugin/share/checkout"], Field(title="Plugin/share/checkoutRequestMethod")
|
||||
]
|
||||
params: PluginShareCheckoutParams
|
||||
|
||||
|
||||
class PluginShareDeleteRequest(BaseModel):
|
||||
model_config = ConfigDict(
|
||||
populate_by_name=True,
|
||||
@@ -5424,6 +5431,7 @@ class ConfigRequirements(BaseModel):
|
||||
model_config = ConfigDict(
|
||||
populate_by_name=True,
|
||||
)
|
||||
allow_managed_hooks_only: Annotated[bool | None, Field(alias="allowManagedHooksOnly")] = None
|
||||
allowed_approval_policies: Annotated[
|
||||
list[AskForApproval] | None, Field(alias="allowedApprovalPolicies")
|
||||
] = None
|
||||
@@ -5851,40 +5859,6 @@ class OverriddenMetadata(BaseModel):
|
||||
overriding_layer: Annotated[ConfigLayerMetadata, Field(alias="overridingLayer")]
|
||||
|
||||
|
||||
class ExternalPermissionProfile(BaseModel):
|
||||
model_config = ConfigDict(
|
||||
populate_by_name=True,
|
||||
)
|
||||
network: PermissionProfileNetworkPermissions
|
||||
type: Annotated[Literal["external"], Field(title="ExternalPermissionProfileType")]
|
||||
|
||||
|
||||
class RestrictedPermissionProfileFileSystemPermissions(BaseModel):
|
||||
model_config = ConfigDict(
|
||||
populate_by_name=True,
|
||||
)
|
||||
entries: list[FileSystemSandboxEntry]
|
||||
glob_scan_max_depth: Annotated[int | None, Field(alias="globScanMaxDepth", ge=1)] = None
|
||||
type: Annotated[
|
||||
Literal["restricted"], Field(title="RestrictedPermissionProfileFileSystemPermissionsType")
|
||||
]
|
||||
|
||||
|
||||
class PermissionProfileFileSystemPermissions(
|
||||
RootModel[
|
||||
RestrictedPermissionProfileFileSystemPermissions
|
||||
| UnrestrictedPermissionProfileFileSystemPermissions
|
||||
]
|
||||
):
|
||||
model_config = ConfigDict(
|
||||
populate_by_name=True,
|
||||
)
|
||||
root: (
|
||||
RestrictedPermissionProfileFileSystemPermissions
|
||||
| UnrestrictedPermissionProfileFileSystemPermissions
|
||||
)
|
||||
|
||||
|
||||
class PluginSharePrincipal(BaseModel):
|
||||
model_config = ConfigDict(
|
||||
populate_by_name=True,
|
||||
@@ -6626,7 +6600,6 @@ class ToolsV2(BaseModel):
|
||||
model_config = ConfigDict(
|
||||
populate_by_name=True,
|
||||
)
|
||||
view_image: bool | None = None
|
||||
web_search: WebSearchToolConfig | None = None
|
||||
|
||||
|
||||
@@ -7072,24 +7045,6 @@ class ListMcpServerStatusResponse(BaseModel):
|
||||
] = None
|
||||
|
||||
|
||||
class ManagedPermissionProfile(BaseModel):
|
||||
model_config = ConfigDict(
|
||||
populate_by_name=True,
|
||||
)
|
||||
file_system: Annotated[PermissionProfileFileSystemPermissions, Field(alias="fileSystem")]
|
||||
network: PermissionProfileNetworkPermissions
|
||||
type: Annotated[Literal["managed"], Field(title="ManagedPermissionProfileType")]
|
||||
|
||||
|
||||
class PermissionProfile(
|
||||
RootModel[ManagedPermissionProfile | DisabledPermissionProfile | ExternalPermissionProfile]
|
||||
):
|
||||
model_config = ConfigDict(
|
||||
populate_by_name=True,
|
||||
)
|
||||
root: ManagedPermissionProfile | DisabledPermissionProfile | ExternalPermissionProfile
|
||||
|
||||
|
||||
class PluginShareContext(BaseModel):
|
||||
model_config = ConfigDict(
|
||||
populate_by_name=True,
|
||||
@@ -7098,6 +7053,13 @@ class PluginShareContext(BaseModel):
|
||||
creator_name: Annotated[str | None, Field(alias="creatorName")] = None
|
||||
discoverability: PluginShareDiscoverability | None = None
|
||||
remote_plugin_id: Annotated[str, Field(alias="remotePluginId")]
|
||||
remote_version: Annotated[
|
||||
str | None,
|
||||
Field(
|
||||
alias="remoteVersion",
|
||||
description="Version of the remote shared plugin release when available.",
|
||||
),
|
||||
] = None
|
||||
share_principals: Annotated[
|
||||
list[PluginSharePrincipal] | None, Field(alias="sharePrincipals")
|
||||
] = None
|
||||
@@ -7129,7 +7091,20 @@ class PluginSummary(BaseModel):
|
||||
installed: bool
|
||||
interface: PluginInterface | None = None
|
||||
keywords: list[str] | None = []
|
||||
local_version: Annotated[
|
||||
str | None,
|
||||
Field(
|
||||
alias="localVersion",
|
||||
description="Version of the locally materialized plugin package when available.",
|
||||
),
|
||||
] = None
|
||||
name: str
|
||||
remote_plugin_id: Annotated[
|
||||
str | None,
|
||||
Field(
|
||||
alias="remotePluginId", description="Backend remote plugin identifier when available."
|
||||
),
|
||||
] = None
|
||||
share_context: Annotated[
|
||||
PluginShareContext | None,
|
||||
Field(
|
||||
@@ -7209,6 +7184,7 @@ class ResponseItem(
|
||||
| WebSearchCallResponseItem
|
||||
| ImageGenerationCallResponseItem
|
||||
| CompactionResponseItem
|
||||
| CompactionTriggerResponseItem
|
||||
| ContextCompactionResponseItem
|
||||
| OtherResponseItem
|
||||
]
|
||||
@@ -7229,6 +7205,7 @@ class ResponseItem(
|
||||
| WebSearchCallResponseItem
|
||||
| ImageGenerationCallResponseItem
|
||||
| CompactionResponseItem
|
||||
| CompactionTriggerResponseItem
|
||||
| ContextCompactionResponseItem
|
||||
| OtherResponseItem
|
||||
)
|
||||
@@ -7448,8 +7425,9 @@ class Config(BaseModel):
|
||||
),
|
||||
] = None
|
||||
compact_prompt: str | None = None
|
||||
desktop: dict[str, Any] | None = None
|
||||
developer_instructions: str | None = None
|
||||
forced_chatgpt_workspace_id: str | None = None
|
||||
forced_chatgpt_workspace_id: ForcedChatgptWorkspaceIds | None = None
|
||||
forced_login_method: ForcedLoginMethod | None = None
|
||||
instructions: str | None = None
|
||||
model: str | None = None
|
||||
@@ -7827,7 +7805,7 @@ class ThreadForkResponse(BaseModel):
|
||||
sandbox: Annotated[
|
||||
SandboxPolicy,
|
||||
Field(
|
||||
description="Legacy sandbox policy retained for compatibility. Experimental clients should prefer `permissionProfile` when they need exact runtime permissions."
|
||||
description="Legacy sandbox policy retained for compatibility. Experimental clients should prefer `activePermissionProfile` for profile provenance."
|
||||
),
|
||||
]
|
||||
service_tier: Annotated[str | None, Field(alias="serviceTier")] = None
|
||||
@@ -7895,7 +7873,7 @@ class ThreadResumeResponse(BaseModel):
|
||||
sandbox: Annotated[
|
||||
SandboxPolicy,
|
||||
Field(
|
||||
description="Legacy sandbox policy retained for compatibility. Experimental clients should prefer `permissionProfile` when they need exact runtime permissions."
|
||||
description="Legacy sandbox policy retained for compatibility. Experimental clients should prefer `activePermissionProfile` for profile provenance."
|
||||
),
|
||||
]
|
||||
service_tier: Annotated[str | None, Field(alias="serviceTier")] = None
|
||||
@@ -7940,7 +7918,7 @@ class ThreadStartResponse(BaseModel):
|
||||
sandbox: Annotated[
|
||||
SandboxPolicy,
|
||||
Field(
|
||||
description="Legacy sandbox policy retained for compatibility. Experimental clients should prefer `permissionProfile` when they need exact runtime permissions."
|
||||
description="Legacy sandbox policy retained for compatibility. Experimental clients should prefer `activePermissionProfile` for profile provenance."
|
||||
),
|
||||
]
|
||||
service_tier: Annotated[str | None, Field(alias="serviceTier")] = None
|
||||
@@ -7998,11 +7976,13 @@ class ClientRequest(
|
||||
| MarketplaceRemoveRequest
|
||||
| MarketplaceUpgradeRequest
|
||||
| PluginListRequest
|
||||
| PluginInstalledRequest
|
||||
| PluginReadRequest
|
||||
| PluginSkillReadRequest
|
||||
| PluginShareSaveRequest
|
||||
| PluginShareUpdateTargetsRequest
|
||||
| PluginShareListRequest
|
||||
| PluginShareCheckoutRequest
|
||||
| PluginShareDeleteRequest
|
||||
| AppListRequest
|
||||
| FsReadFileRequest
|
||||
@@ -8079,11 +8059,13 @@ class ClientRequest(
|
||||
| MarketplaceRemoveRequest
|
||||
| MarketplaceUpgradeRequest
|
||||
| PluginListRequest
|
||||
| PluginInstalledRequest
|
||||
| PluginReadRequest
|
||||
| PluginSkillReadRequest
|
||||
| PluginShareSaveRequest
|
||||
| PluginShareUpdateTargetsRequest
|
||||
| PluginShareListRequest
|
||||
| PluginShareCheckoutRequest
|
||||
| PluginShareDeleteRequest
|
||||
| AppListRequest
|
||||
| FsReadFileRequest
|
||||
@@ -8135,6 +8117,16 @@ class ClientRequest(
|
||||
]
|
||||
|
||||
|
||||
class PluginInstalledResponse(BaseModel):
|
||||
model_config = ConfigDict(
|
||||
populate_by_name=True,
|
||||
)
|
||||
marketplace_load_errors: Annotated[
|
||||
list[MarketplaceLoadErrorInfo] | None, Field(alias="marketplaceLoadErrors")
|
||||
] = []
|
||||
marketplaces: list[PluginMarketplaceEntry]
|
||||
|
||||
|
||||
class PluginListResponse(BaseModel):
|
||||
model_config = ConfigDict(
|
||||
populate_by_name=True,
|
||||
|
||||
@@ -158,8 +158,8 @@ def test_schema_normalization_only_flattens_string_literal_oneofs(
|
||||
"AuthMode",
|
||||
"InputModality",
|
||||
"ExperimentalFeatureStage",
|
||||
"CommandExecOutputStream",
|
||||
"ProcessOutputStream",
|
||||
"CommandExecOutputStream",
|
||||
]
|
||||
|
||||
|
||||
@@ -249,11 +249,11 @@ def test_source_sdk_package_pins_published_runtime() -> None:
|
||||
"runtime_pin": script.pinned_runtime_version(),
|
||||
"dependencies": pyproject["project"]["dependencies"],
|
||||
} == {
|
||||
"sdk_version": "0.131.0a4",
|
||||
"runtime_pin": "0.131.0a4",
|
||||
"sdk_version": "0.1.0b1",
|
||||
"runtime_pin": "0.132.0",
|
||||
"dependencies": [
|
||||
"pydantic>=2.12",
|
||||
"openai-codex-cli-bin==0.131.0a4",
|
||||
"openai-codex-cli-bin==0.132.0",
|
||||
],
|
||||
}
|
||||
|
||||
@@ -284,19 +284,26 @@ def test_release_metadata_retries_without_invalid_auth(
|
||||
assert authorizations == ["Bearer invalid-token", None]
|
||||
|
||||
|
||||
def test_runtime_setup_uses_pep440_package_version_and_codex_release_tags() -> None:
|
||||
"""The SDK uses PEP 440 package pins and converts only when fetching releases."""
|
||||
def test_runtime_setup_reads_independent_runtime_pin_and_release_tags() -> None:
|
||||
"""Runtime package pins remain independent of the SDK beta version."""
|
||||
runtime_setup = _load_runtime_setup_module()
|
||||
pyproject = tomllib.loads((ROOT / "pyproject.toml").read_text())
|
||||
|
||||
assert runtime_setup.PACKAGE_NAME == "openai-codex-cli-bin"
|
||||
assert runtime_setup.pinned_runtime_version() == pyproject["project"]["version"]
|
||||
assert (
|
||||
f"{runtime_setup.PACKAGE_NAME}=={pyproject['project']['version']}"
|
||||
in pyproject["project"]["dependencies"]
|
||||
)
|
||||
assert runtime_setup._normalized_package_version("rust-v0.116.0-alpha.1") == "0.116.0a1"
|
||||
assert runtime_setup._release_tag("0.116.0a1") == "rust-v0.116.0-alpha.1"
|
||||
assert {
|
||||
"package_name": runtime_setup.PACKAGE_NAME,
|
||||
"sdk_version": pyproject["project"]["version"],
|
||||
"runtime_pin": runtime_setup.pinned_runtime_version(),
|
||||
"normalized_release_version": runtime_setup._normalized_package_version(
|
||||
"rust-v0.116.0-alpha.1"
|
||||
),
|
||||
"release_tag": runtime_setup._release_tag("0.116.0a1"),
|
||||
} == {
|
||||
"package_name": "openai-codex-cli-bin",
|
||||
"sdk_version": "0.1.0b1",
|
||||
"runtime_pin": "0.132.0",
|
||||
"normalized_release_version": "0.116.0a1",
|
||||
"release_tag": "rust-v0.116.0-alpha.1",
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
@@ -491,23 +498,32 @@ def test_runtime_package_layout_is_included_by_wheel_config(
|
||||
]
|
||||
|
||||
|
||||
def test_stage_sdk_release_injects_exact_runtime_pin(tmp_path: Path) -> None:
|
||||
def test_stage_sdk_release_preserves_reviewed_runtime_pin(tmp_path: Path) -> None:
|
||||
script = _load_update_script_module()
|
||||
staged = script.stage_python_sdk_package(
|
||||
tmp_path / "sdk-stage",
|
||||
"rust-v0.116.0-alpha.1",
|
||||
"0.1.0b1",
|
||||
)
|
||||
|
||||
pyproject = (staged / "pyproject.toml").read_text()
|
||||
assert 'name = "openai-codex"' in pyproject
|
||||
assert 'version = "0.116.0a1"' in pyproject
|
||||
assert '"openai-codex-cli-bin==0.116.0a1"' in pyproject
|
||||
pyproject = tomllib.loads((staged / "pyproject.toml").read_text())
|
||||
assert {
|
||||
"name": pyproject["project"]["name"],
|
||||
"version": pyproject["project"]["version"],
|
||||
"dependencies": pyproject["project"]["dependencies"],
|
||||
} == {
|
||||
"name": "openai-codex",
|
||||
"version": "0.1.0b1",
|
||||
"dependencies": [
|
||||
"pydantic>=2.12",
|
||||
"openai-codex-cli-bin==0.132.0",
|
||||
],
|
||||
}
|
||||
assert (
|
||||
'__version__ = "0.116.0a1"'
|
||||
'__version__ = "0.1.0b1"'
|
||||
not in (staged / "src" / "openai_codex" / "__init__.py").read_text()
|
||||
)
|
||||
assert (
|
||||
'client_version: str = "0.116.0a1"'
|
||||
'client_version: str = "0.1.0b1"'
|
||||
not in (staged / "src" / "openai_codex" / "client.py").read_text()
|
||||
)
|
||||
assert not any((staged / "src" / "openai_codex").glob("bin/**"))
|
||||
@@ -520,34 +536,41 @@ def test_stage_sdk_release_replaces_existing_staging_dir(tmp_path: Path) -> None
|
||||
old_file.parent.mkdir(parents=True)
|
||||
old_file.write_text("stale")
|
||||
|
||||
staged = script.stage_python_sdk_package(staging_dir, "0.116.0a1")
|
||||
staged = script.stage_python_sdk_package(staging_dir, "0.1.0b1")
|
||||
|
||||
assert staged == staging_dir
|
||||
assert not old_file.exists()
|
||||
|
||||
|
||||
def test_staged_sdk_and_runtime_versions_match(tmp_path: Path) -> None:
|
||||
def test_sdk_beta_release_can_pin_stable_runtime(tmp_path: Path) -> None:
|
||||
script = _load_update_script_module()
|
||||
package_archive = _write_fake_codex_package_archive(tmp_path, script)
|
||||
|
||||
sdk_stage = script.stage_python_sdk_package(
|
||||
tmp_path / "sdk-stage",
|
||||
"rust-v0.116.0-alpha.1",
|
||||
"0.1.0b1",
|
||||
)
|
||||
runtime_stage = script.stage_python_runtime_package(
|
||||
tmp_path / "runtime-stage",
|
||||
"rust-v0.116.0-alpha.1",
|
||||
"0.132.0",
|
||||
package_archive,
|
||||
)
|
||||
|
||||
sdk_pyproject = tomllib.loads((sdk_stage / "pyproject.toml").read_text())
|
||||
runtime_pyproject = tomllib.loads((runtime_stage / "pyproject.toml").read_text())
|
||||
|
||||
assert sdk_pyproject["project"]["version"] == runtime_pyproject["project"]["version"]
|
||||
assert sdk_pyproject["project"]["dependencies"] == [
|
||||
"pydantic>=2.12",
|
||||
"openai-codex-cli-bin==0.116.0a1",
|
||||
]
|
||||
assert {
|
||||
"sdk_version": sdk_pyproject["project"]["version"],
|
||||
"runtime_version": runtime_pyproject["project"]["version"],
|
||||
"sdk_dependencies": sdk_pyproject["project"]["dependencies"],
|
||||
} == {
|
||||
"sdk_version": "0.1.0b1",
|
||||
"runtime_version": "0.132.0",
|
||||
"sdk_dependencies": [
|
||||
"pydantic>=2.12",
|
||||
"openai-codex-cli-bin==0.132.0",
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
def test_stage_sdk_runs_type_generation_before_staging(tmp_path: Path) -> None:
|
||||
@@ -557,16 +580,16 @@ def test_stage_sdk_runs_type_generation_before_staging(tmp_path: Path) -> None:
|
||||
[
|
||||
"stage-sdk",
|
||||
str(tmp_path / "sdk-stage"),
|
||||
"--codex-version",
|
||||
"rust-v0.116.0-alpha.1",
|
||||
"--sdk-version",
|
||||
"0.1.0b1",
|
||||
]
|
||||
)
|
||||
|
||||
def fake_generate_types() -> None:
|
||||
calls.append("generate_types")
|
||||
|
||||
def fake_stage_sdk_package(_staging_dir: Path, codex_version: str) -> Path:
|
||||
calls.append(f"stage_sdk:{codex_version}")
|
||||
def fake_stage_sdk_package(_staging_dir: Path, sdk_version: str) -> Path:
|
||||
calls.append(f"stage_sdk:{sdk_version}")
|
||||
return tmp_path / "sdk-stage"
|
||||
|
||||
def fake_stage_runtime_package(
|
||||
@@ -589,26 +612,7 @@ def test_stage_sdk_runs_type_generation_before_staging(tmp_path: Path) -> None:
|
||||
|
||||
script.run_command(args, ops)
|
||||
|
||||
assert calls == ["generate_types", "stage_sdk:0.116.0a1"]
|
||||
|
||||
|
||||
def test_stage_sdk_rejects_mismatched_legacy_versions(tmp_path: Path) -> None:
|
||||
script = _load_update_script_module()
|
||||
args = script.parse_args(
|
||||
[
|
||||
"stage-sdk",
|
||||
str(tmp_path / "sdk-stage"),
|
||||
"--codex-version",
|
||||
"0.116.0a1",
|
||||
"--runtime-version",
|
||||
"0.116.0a1",
|
||||
"--sdk-version",
|
||||
"0.115.0",
|
||||
]
|
||||
)
|
||||
|
||||
with pytest.raises(RuntimeError, match="versions must match"):
|
||||
script.run_command(args, script.default_cli_ops())
|
||||
assert calls == ["generate_types", "stage_sdk:0.1.0b1"]
|
||||
|
||||
|
||||
def test_stage_runtime_stages_package_without_type_generation(tmp_path: Path) -> None:
|
||||
|
||||
@@ -40,7 +40,7 @@ def test_generated_files_are_up_to_date():
|
||||
|
||||
# Regenerate contract artifacts via the pinned runtime package, not a local
|
||||
# app-server binary from the checkout or CI environment.
|
||||
assert importlib.metadata.version("openai-codex-cli-bin") == "0.131.0a4"
|
||||
assert importlib.metadata.version("openai-codex-cli-bin") == "0.132.0"
|
||||
env = os.environ.copy()
|
||||
env.pop("CODEX_EXEC_PATH", None)
|
||||
python_bin = str(Path(sys.executable).parent)
|
||||
|
||||
Generated
+16
-9
@@ -2,6 +2,13 @@ version = 1
|
||||
revision = 3
|
||||
requires-python = ">=3.10"
|
||||
|
||||
[options]
|
||||
exclude-newer = "0001-01-01T00:00:00Z" # This has no effect and is included for backwards compatibility when using relative exclude-newer values.
|
||||
exclude-newer-span = "P7D"
|
||||
|
||||
[options.exclude-newer-package]
|
||||
openai-codex-cli-bin = "2026-05-20T21:00:00Z"
|
||||
|
||||
[[package]]
|
||||
name = "annotated-types"
|
||||
version = "0.7.0"
|
||||
@@ -275,7 +282,7 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "openai-codex"
|
||||
version = "0.131.0a4"
|
||||
version = "0.1.0b1"
|
||||
source = { editable = "." }
|
||||
dependencies = [
|
||||
{ name = "openai-codex-cli-bin" },
|
||||
@@ -292,7 +299,7 @@ dev = [
|
||||
[package.metadata]
|
||||
requires-dist = [
|
||||
{ name = "datamodel-code-generator", marker = "extra == 'dev'", specifier = "==0.31.2" },
|
||||
{ name = "openai-codex-cli-bin", specifier = "==0.131.0a4" },
|
||||
{ name = "openai-codex-cli-bin", specifier = "==0.132.0" },
|
||||
{ name = "pydantic", specifier = ">=2.12" },
|
||||
{ name = "pytest", marker = "extra == 'dev'", specifier = ">=8.0" },
|
||||
{ name = "ruff", marker = "extra == 'dev'", specifier = ">=0.15.8" },
|
||||
@@ -301,15 +308,15 @@ provides-extras = ["dev"]
|
||||
|
||||
[[package]]
|
||||
name = "openai-codex-cli-bin"
|
||||
version = "0.131.0a4"
|
||||
version = "0.132.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/6b/9f/f9fc4bb1b2b7a20d4d65143ebb4c4dcd2301a718183b539ecb5b1c0ac3ec/openai_codex_cli_bin-0.131.0a4-py3-none-macosx_10_9_x86_64.whl", hash = "sha256:db0f3cb7dda310641ac04fbaf3f128693a3817ab83ae59b67a3c9c74bd53f8b8", size = 88367585, upload-time = "2026-05-09T06:14:09.453Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/dc/39/eb95ed0e8156669e895a192dec760be07dabe891c3c6340f7c6487b9a976/openai_codex_cli_bin-0.131.0a4-py3-none-macosx_11_0_arm64.whl", hash = "sha256:6cae5af6edca7f6d3f0bcbbd93cfc8a6dc3e33fb5955af21ae492b6d5d0dcb72", size = 79245567, upload-time = "2026-05-09T06:14:13.581Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0c/92/ade176fa78d746d5ff7a6e371d64740c0d95ab299b0dd58a5404b89b3915/openai_codex_cli_bin-0.131.0a4-py3-none-musllinux_1_1_aarch64.whl", hash = "sha256:5728f9887baf62d7e72f4f242093b3ff81e26c81d80d346fe1eef7eda6838aa8", size = 77758628, upload-time = "2026-05-09T06:14:18.374Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/28/e6/bfe6c65f8e3e5499f71b24c3b6e8d07e4d426543d25e429b9b141b544e5f/openai_codex_cli_bin-0.131.0a4-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:d7a47fd3667fbcc216593839c202deffa056e9b3d46c6933e72594d461f4fea0", size = 84535509, upload-time = "2026-05-09T06:14:22.851Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/bd/b7/53dc094a691ab6f2ca079e8e865b122843809ac4fad51cac4d59021e599d/openai_codex_cli_bin-0.131.0a4-py3-none-win_amd64.whl", hash = "sha256:c61bcf029672494c4c7fdc8567dbaa659a48bb75641d91c2ade27c1e46803434", size = 88185543, upload-time = "2026-05-09T06:14:27.282Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/82/99/e0852ffcf9b4d2794fef83e0c3a267b3c773a776f136e9f7ce19f0c8df42/openai_codex_cli_bin-0.131.0a4-py3-none-win_arm64.whl", hash = "sha256:bbde750186861f102e346ac066f4e9608f515f7b71b16a6e8b7ef1ddc02a97a5", size = 81196380, upload-time = "2026-05-09T06:14:32.103Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/be/a1/b92b7a1b73a83785d2e1dcd0faecd1b7f886a38cf02a30abe1c35f42f0f7/openai_codex_cli_bin-0.132.0-py3-none-macosx_10_9_x86_64.whl", hash = "sha256:1c22b51dbd679413f84f00b9d8fd4e5cf8a1c0d1c7cc8c42bcb3f9f1b33e2334", size = 89403211, upload-time = "2026-05-20T02:37:22.311Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5f/68/163272e582de55a7f460e2329281267908d75d0fbcbbbb2c6749a6329e6b/openai_codex_cli_bin-0.132.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:56217495e6635c8a5d96df820cc0da5f46cd9b6ec6f3a5f67f1607d69ef74256", size = 79058685, upload-time = "2026-05-20T02:37:27.165Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0b/18/a60c6b137e7cd3959cae16ba757f57ca5702979b0ea107a21f516ba15d98/openai_codex_cli_bin-0.132.0-py3-none-musllinux_1_1_aarch64.whl", hash = "sha256:09642e7578a3078bfccc82af4077b085d42b0022b529e4b5c645e0a0af3397a4", size = 78689038, upload-time = "2026-05-20T02:37:31.548Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f8/eb/1b184307a67c1006d59b61636bcfcea73a89aa95271f6516ed28dce554ca/openai_codex_cli_bin-0.132.0-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:85aec095f9d144d7a2d1aff39fce77b7240f42014580c35801ba74b9317aa5f7", size = 85528820, upload-time = "2026-05-20T02:37:36.559Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0e/e8/1b823a8bf7b96d1513905ad79b16a146d797f81a19a6bc350a2f95a16661/openai_codex_cli_bin-0.132.0-py3-none-win_amd64.whl", hash = "sha256:3cb5c90c55baa39bd5ddc890d2068d3e1322a57a54d1d0e623819009a205c7f5", size = 86916218, upload-time = "2026-05-20T02:37:41.886Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6b/e6/bb8634bd4f3adaea299c95d7b03105ac417e32dd6d8bc2af5dda141d6f28/openai_codex_cli_bin-0.132.0-py3-none-win_arm64.whl", hash = "sha256:74ef93d3deef7cb83c71d19fc667defe749cdab337ec331f59a23511561b6f6a", size = 79892931, upload-time = "2026-05-20T02:37:46.828Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
Reference in New Issue
Block a user