from __future__ import annotations from dataclasses import dataclass from typing import Protocol from .async_client import AsyncCodexClient from .client import CodexClient from .generated.v2_all import ( AccountLoginCompletedNotification, CancelLoginAccountResponse, ChatgptDeviceCodeLoginAccountParams, ChatgptDeviceCodeLoginAccountResponse, ChatgptLoginAccountParams, ChatgptLoginAccountResponse, LoginAccountParams, ) class _AsyncLoginOwner(Protocol): """Subset of AsyncCodex needed by async login handles.""" _client: AsyncCodexClient async def _ensure_initialized(self) -> None: """Ensure the owning SDK client has a live Codex connection.""" ... def start_chatgpt_login(client: CodexClient) -> ChatgptLoginHandle: """Start browser ChatGPT login and return the handle for that attempt.""" response = client.account_login_start( LoginAccountParams( root=ChatgptLoginAccountParams(type="chatgpt"), ) ) response_root = response.root if not isinstance(response_root, ChatgptLoginAccountResponse): raise RuntimeError(f"unexpected ChatGPT login response: {response_root!r}") return ChatgptLoginHandle( client, response_root.login_id, response_root.auth_url, ) async def async_start_chatgpt_login(owner: _AsyncLoginOwner) -> AsyncChatgptLoginHandle: """Start async browser ChatGPT login and return that attempt's handle.""" response = await owner._client.account_login_start( LoginAccountParams( root=ChatgptLoginAccountParams(type="chatgpt"), ) ) response_root = response.root if not isinstance(response_root, ChatgptLoginAccountResponse): raise RuntimeError(f"unexpected ChatGPT login response: {response_root!r}") return AsyncChatgptLoginHandle( owner, response_root.login_id, response_root.auth_url, ) def start_device_code_login(client: CodexClient) -> DeviceCodeLoginHandle: """Start device-code ChatGPT login and return the handle for that attempt.""" response = client.account_login_start( LoginAccountParams( root=ChatgptDeviceCodeLoginAccountParams(type="chatgptDeviceCode"), ) ) response_root = response.root if not isinstance(response_root, ChatgptDeviceCodeLoginAccountResponse): raise RuntimeError(f"unexpected device-code login response: {response_root!r}") return DeviceCodeLoginHandle( client, response_root.login_id, response_root.verification_url, response_root.user_code, ) async def async_start_device_code_login( owner: _AsyncLoginOwner, ) -> AsyncDeviceCodeLoginHandle: """Start async device-code ChatGPT login and return that attempt's handle.""" response = await owner._client.account_login_start( LoginAccountParams( root=ChatgptDeviceCodeLoginAccountParams(type="chatgptDeviceCode"), ) ) response_root = response.root if not isinstance(response_root, ChatgptDeviceCodeLoginAccountResponse): raise RuntimeError(f"unexpected device-code login response: {response_root!r}") return AsyncDeviceCodeLoginHandle( owner, response_root.login_id, response_root.verification_url, response_root.user_code, ) @dataclass(slots=True) class ChatgptLoginHandle: """Live browser-login attempt returned by `Codex.login_chatgpt()`.""" _client: CodexClient login_id: str auth_url: str def wait(self) -> AccountLoginCompletedNotification: """Wait for this browser login attempt's completion notification.""" return self._client.wait_for_login_completed(self.login_id) def cancel(self) -> CancelLoginAccountResponse: """Cancel this browser login attempt.""" return self._client.account_login_cancel(self.login_id) @dataclass(slots=True) class DeviceCodeLoginHandle: """Live device-code login attempt returned by `Codex.login_chatgpt_device_code()`.""" _client: CodexClient login_id: str verification_url: str user_code: str def wait(self) -> AccountLoginCompletedNotification: """Wait for this device-code login attempt's completion notification.""" return self._client.wait_for_login_completed(self.login_id) def cancel(self) -> CancelLoginAccountResponse: """Cancel this device-code login attempt.""" return self._client.account_login_cancel(self.login_id) @dataclass(slots=True) class AsyncChatgptLoginHandle: """Live browser-login attempt returned by `AsyncCodex.login_chatgpt()`.""" _codex: _AsyncLoginOwner login_id: str auth_url: str async def wait(self) -> AccountLoginCompletedNotification: """Wait for this browser login attempt's completion notification.""" await self._codex._ensure_initialized() return await self._codex._client.wait_for_login_completed(self.login_id) async def cancel(self) -> CancelLoginAccountResponse: """Cancel this browser login attempt.""" await self._codex._ensure_initialized() return await self._codex._client.account_login_cancel(self.login_id) @dataclass(slots=True) class AsyncDeviceCodeLoginHandle: """Live device-code attempt returned by `AsyncCodex.login_chatgpt_device_code()`.""" _codex: _AsyncLoginOwner login_id: str verification_url: str user_code: str async def wait(self) -> AccountLoginCompletedNotification: """Wait for this device-code login attempt's completion notification.""" await self._codex._ensure_initialized() return await self._codex._client.wait_for_login_completed(self.login_id) async def cancel(self) -> CancelLoginAccountResponse: """Cancel this device-code login attempt.""" await self._codex._ensure_initialized() return await self._codex._client.account_login_cancel(self.login_id)