Test Python SDK against the built CLI and installed runtime (#44053)

## Why

Python SDK CI needs to exercise the checkout's CLI while retaining coverage of the wheel installation and its default runtime.

## What changed

- Run the Python SDK test suite against the same Bazel-built CLI as the TypeScript SDK tests. Build and stage `codex-code-mode-host` alongside the CLI so it can be discovered.
- Make the Python test harness prefer `CODEX_EXEC_PATH`, then a local debug build, then the installed runtime. Exclude optional turn-cost probes from recorded model requests.
- Add a separate installation job that builds the Python SDK wheel and installs it in a fresh environment.

## Testing

The installation smoke test verifies that imports resolve to the installed SDK and that its default runtime completes a mocked turn with the expected user input and final response.

GitOrigin-RevId: 8e3126742a014e2cf042afe799bc657e1ea2a282
This commit is contained in:
Ahmed Ibrahim
2026-09-09 04:29:49 +00:00
committed by copyberry
parent 9ba1d9eb5b
commit c55db1b8d9
3 changed files with 82 additions and 44 deletions

View File

@@ -1,6 +1,7 @@
from __future__ import annotations
import json
import os
import queue
import shutil
import threading
@@ -204,7 +205,7 @@ class MockResponsesServer:
class AppServerHarness:
"""Test fixture that points a pinned runtime app-server at MockResponsesServer."""
"""Test fixture that points the checkout's app-server at MockResponsesServer."""
def __init__(self, tmp_path: Path, *, requires_openai_auth: bool = False) -> None:
self.tmp_path = tmp_path
@@ -226,8 +227,14 @@ class AppServerHarness:
shutil.rmtree(self.workspace, ignore_errors=True)
def app_server_config(self) -> CodexConfig:
"""Build SDK config for an isolated pinned-runtime app-server process."""
"""Prefer the CI binary, then a local debug build, then the installed runtime."""
binary_name = "codex.exe" if os.name == "nt" else "codex"
debug_binary = Path(__file__).resolve().parents[3] / "codex-rs/target/debug" / binary_name
codex_bin = os.environ.get("CODEX_EXEC_PATH")
if codex_bin is None and debug_binary.is_file():
codex_bin = str(debug_binary)
return CodexConfig(
codex_bin=codex_bin,
cwd=str(self.workspace),
env={
"CODEX_HOME": str(self.codex_home),
@@ -304,6 +311,10 @@ class _ResponsesHandler(BaseHTTPRequestHandler):
"""Serve queued SSE responses for `/v1/responses` requests."""
length = int(self.headers.get("content-length", "0"))
body = self.rfile.read(length)
if self.path.endswith("/analytics/codex/turn-costs"):
# Optional cost probes are not model requests.
self.send_error(404, "turn costs are unavailable for the mock provider")
return
self.server.mock._record_request(self, body)
if not (self.path.endswith("/v1/responses") or self.path.endswith("/responses")):

View File

@@ -0,0 +1,34 @@
"""Exercise a built SDK's default runtime in an otherwise isolated environment."""
from dataclasses import replace
from importlib.metadata import distribution, version
from pathlib import Path
from tempfile import TemporaryDirectory
from app_server_harness import AppServerHarness
import openai_codex
from openai_codex import Codex
def main() -> None:
installed_root = Path(distribution("openai-codex").locate_file("")).resolve()
assert Path(openai_codex.__file__).resolve().is_relative_to(installed_root), (
"The smoke test must import the installed SDK, not the source checkout"
)
with TemporaryDirectory() as directory, AppServerHarness(Path(directory)) as harness:
harness.responses.enqueue_assistant_message("Installed SDK works")
config = replace(harness.app_server_config(), codex_bin=None)
with Codex(config=config) as codex:
result = codex.thread_start().run("Check the installed SDK")
assert result.final_response == "Installed SDK works"
assert harness.responses.single_request().message_input_texts("user")[-1:] == [
"Check the installed SDK"
]
print(f"Installed SDK passed with CLI runtime {version('openai-codex-cli-bin')}")
if __name__ == "__main__":
main()