feat(llm): Add subscription-based authentication for OpenAI Codex models#1682
feat(llm): Add subscription-based authentication for OpenAI Codex models#1682
Conversation
Implement OAuth PKCE flow for authenticating with OpenAI's ChatGPT service, allowing users with ChatGPT Plus/Pro subscriptions to use Codex models (gpt-5.2-codex, gpt-5.2, gpt-5.1-codex-max, gpt-5.1-codex-mini) without consuming API credits. Key features: - OAuth PKCE flow with local callback server for secure authentication - Credential storage with automatic token refresh - LLM.subscription_login() classmethod for easy access - Support for multiple Codex models via ChatGPT subscription Usage: from openhands.sdk import LLM llm = LLM.subscription_login(model='gpt-5.2-codex') Inspired by opencode's implementation (anomalyco/opencode#7537). Co-authored-by: openhands <openhands@all-hands.dev>
Coverage Report •
|
|||||||||||||||||||||||||||||||||||
- Use authlib for PKCE generation (generate_token, create_s256_code_challenge) - Use aiohttp.web for OAuth callback server (cleaner than raw asyncio) - Add Codex-specific parameters (store=false, instructions) via litellm_extra_body - Add max_output_tokens=None for Codex (not supported by the API) - Reduce code from ~575 lines to ~492 lines This addresses the 'Instructions are not valid' error by properly configuring the Codex API parameters. Co-authored-by: openhands <openhands@all-hands.dev>
|
@OpenHands /codereview-roasted and help me fix all the issues and make sure pre-commit run --all-files pass |
|
I'm on it! xingyaoww can track my progress at all-hands.dev |
- Move time import to module level in credentials.py - Replace os.uname() with platform.system()/machine() for cross-platform compatibility - Move urllib.parse.urlencode import to module level in openai.py - Remove extra blank line before __all__ in auth/__init__.py - Apply ruff formatting fixes to llm.py Co-authored-by: openhands <openhands@all-hands.dev>
SummaryI completed the roasted code review and fixed all identified issues. The changes have been pushed to the Code Review (Linus-Style) 🔴 Needs ImprovementCritical Issues Fixed:
Style Fixes: Changes Made (3 files, -6 lines net)
Verification ✅
The PR is now updated at: #1682 |
Refactor the inline subscription transport check to a reusable @Property method on the LLM class. This improves code readability and allows the subscription check to be used elsewhere if needed. Co-authored-by: openhands <openhands@all-hands.dev>
… heuristics - Add _is_subscription private attribute to LLM class (default False) - Update is_subscription property to use the attribute directly - Set _is_subscription=True in OpenAISubscriptionAuth.create_llm() - Update tests to explicitly set _is_subscription for subscription tests - Add example file for subscription login usage This removes the URL-based heuristics and ensures is_subscription only returns True for LLMs created via LLM.subscription_login(). Co-authored-by: openhands <openhands@all-hands.dev>
- Hardcode stream=True, temperature=None, max_output_tokens=None in subscription_login - Skip unsupported parameters in responses_options for subscription mode - Force parameters to None after LLM init to prevent auto-detection from model info Fixes API errors: 'Unsupported parameter: max_output_tokens', 'Unsupported parameter: temperature', 'Stream must be set to true' Co-authored-by: openhands <openhands@all-hands.dev>
|
@OpenHands review diff against main, understand the purpose of this PR, then open a new PR in OpenHands/docs repo to document the new feature added in this PR. The doc should appear under |
|
I'm on it! xingyaoww can track my progress at all-hands.dev |
Add a Literal type alias SupportedVendor = Literal["openai"] for the vendor parameter in subscription_login methods. This provides better type safety and makes it easier to add more vendors in the future. Changes: - Define SupportedVendor type in openhands/sdk/llm/auth/openai.py - Export SupportedVendor from openhands/sdk/llm/auth/__init__.py - Update vendor parameter type in: - LLM.subscription_login() - subscription_login() - subscription_login_async() Co-authored-by: openhands <openhands@all-hands.dev>
…hentication This adds documentation for the new subscription_login() feature that allows users to authenticate with their ChatGPT Plus/Pro subscription to access Codex models without consuming API credits. Key features documented: - OAuth PKCE authentication flow - Credential caching and automatic token refresh - Supported models (gpt-5.2-codex, gpt-5.2, gpt-5.1-codex-max, gpt-5.1-codex-mini) - Configuration options (force_login, open_browser) - Credential storage location Related SDK PR: OpenHands/software-agent-sdk#1682 Co-authored-by: openhands <openhands@all-hands.dev>
- Extract subscription-specific message transformation into dedicated methods (_transform_for_subscription, _inject_system_prefix) - Use list comprehension for message normalization - Consolidate create_llm method in OpenAISubscriptionAuth - Reduce code duplication and improve readability - Fix test assertion to match actual originator header value Co-authored-by: openhands <openhands@all-hands.dev>
|
@OpenHands please fix the failing actions on PR #1682 at branch Review diff from main, understand the purpose of this PR, and help me update OpenHands/docs#267 with the latest state of this PR |
|
I'm on it! xingyaoww can track my progress at all-hands.dev |
SummaryI've successfully fixed the failing GitHub Actions on PR #1682 and updated the docs PR #267. Problem IdentifiedThe CI workflow "[Optional] Docs example" was failing because two SDK examples were undocumented:
Changes Made to OpenHands/docs PR #2671. Fixed
2. Created new
3. Updated
Verification
Links |
|
Tested and confirm it works - gonna merge it for next release |
- Remove CONSENT_DISCLAIMER constant and related verbose display logic - Simplify _display_consent_and_confirm() function by removing verbose parameter - Remove verbose parameter from subscription_login_async and subscription_login - Update tests to reflect the simplified consent flow
|
@OpenHands please fix the failing actions on PR #1682 at branch Do not change implementation, just fix the tests |
|
I'm on it! xingyaoww can track my progress at all-hands.dev |
…mentation The tests were expecting ~/.local/share/openhands/auth but the implementation uses ~/.openhands/auth. Updated tests to match the actual implementation. Co-authored-by: openhands <openhands@all-hands.dev>
SummaryI fixed the failing tests in PR #1682 on branch IssueTwo tests in
But the actual implementation in FixUpdated the tests to match the actual implementation (as requested - no implementation changes):
Verification
The CI should now pass for the sdk-tests job. |
|
Looks like there are a few issues preventing this PR from being merged!
If you'd like me to help, just leave a comment, like Feel free to include any additional details that might help me get this PR into a better state. You can manage your notification settings |
|
Yes, it does work! It looks fairly good to me. I'm very glad that the vast majority of the code is in separate files, so we can find it easy to make it into an extension later. @OpenHands Look at the entire branch including responses() API path in llm.py, and the file openai.py, and tell me:
Investigate the entire instructions and system message event, including suffixes. Do not make any modifications, I just want the complete answer, post it as comment on github here, use remote gh. Note that it will be rendered as markdown. |
|
I'm on it! enyst can track my progress at all-hands.dev |
Subscription mode: instructions sent to LLM (Responses API)
(defined as Subscription mode: what is prepended to the first user message
(note the trailing blank line; this is the literal
Notes on suffixes / separators
|
This comment was marked as duplicate.
This comment was marked as duplicate.
Skills / AgentSkills “system suffix” behavior in subscription mode
|
Tools + system prompt event (concise)
|
…hentication (#267) * docs: Add LLM subscriptions guide for OpenAI ChatGPT subscription authentication This adds documentation for the new subscription_login() feature that allows users to authenticate with their ChatGPT Plus/Pro subscription to access Codex models without consuming API credits. Key features documented: - OAuth PKCE authentication flow - Credential caching and automatic token refresh - Supported models (gpt-5.2-codex, gpt-5.2, gpt-5.1-codex-max, gpt-5.1-codex-mini) - Configuration options (force_login, open_browser) - Credential storage location Related SDK PR: OpenHands/software-agent-sdk#1682 Co-authored-by: openhands <openhands@all-hands.dev> * docs: Update subscription login example path and add critic documentation - Fix subscription_login example path from 34 to 35 - Add vendor='openai' parameter to all code examples - Update code to match actual SDK example - Add new critic.mdx documentation for 34_critic_example.py - Add critic page to Agent Features navigation group Co-authored-by: openhands <openhands@all-hands.dev> * docs: Update LLM subscriptions guide and add ChatGPT login option to quickstart - Update credential storage path from ~/.local/share/openhands/auth/ to ~/.openhands/auth/ to match SDK PR #1682 - Fix example directory name from agent-sdk to software-agent-sdk - Add ChatGPT Subscription as third option in how-to-run-example.mdx - Add Tip component linking to LLM Subscriptions guide Co-authored-by: openhands <openhands@all-hands.dev> * Apply suggestion from @xingyaoww * docs: Simplify ChatGPT subscription option to Tip with link Remove code block for ChatGPT subscription option and keep it as a Tip component that links to the LLM Subscriptions guide. Co-authored-by: openhands <openhands@all-hands.dev> * docs: Refactor llm-subscriptions.mdx to follow guide format - Add import for RunExampleCode shared snippet - Add 'ready-to-run example' link at top - Restructure 'How It Works' section using Steps/Step components - Move 'Ready-to-run Example' section to end (before Next Steps) - Add RunExampleCode component after code block - Add icon='python' to all code blocks Co-authored-by: openhands <openhands@all-hands.dev> * docs: Simplify llm-subscriptions.mdx - remove technical details - Remove OAuth PKCE flow details (keep it high-level) - Remove Automatic Token Management step (merge into step 2) - Simplify Credential Storage section Co-authored-by: openhands <openhands@all-hands.dev> * docs: Add ChatGPT subscription option to getting-started and update AGENTS.md - Add Option 3: ChatGPT Subscription to getting-started.mdx AccordionGroup - Add 'LLM API Key Options' section to AGENTS.md documenting the three ways users can obtain LLM access for future reference Co-authored-by: openhands <openhands@all-hands.dev> * Update sdk/guides/llm-subscriptions.mdx Co-authored-by: Engel Nyst <engel.nyst@gmail.com> --------- Co-authored-by: openhands <openhands@all-hands.dev> Co-authored-by: Engel Nyst <engel.nyst@gmail.com>
Summary
This PR implements OAuth PKCE flow for authenticating with OpenAI's ChatGPT service, allowing users with ChatGPT Plus/Pro subscriptions to use Codex models without consuming API credits.
Key features:
~/.local/share/openhands/auth/)LLM.subscription_login()classmethod for easy accessgpt-5.2-codexgpt-5.2gpt-5.1-codex-maxgpt-5.1-codex-miniUsage:
Implementation inspired by: opencode's implementation
New modules:
openhands/sdk/llm/auth/__init__.py- Auth module exportsopenhands/sdk/llm/auth/credentials.py- Credential storage and retrievalopenhands/sdk/llm/auth/openai.py- OpenAI OAuth PKCE flow implementationChecklist
Note: This feature requires a ChatGPT Plus/Pro subscription to test the actual OAuth flow. The unit tests cover the credential storage, PKCE generation, URL building, and mock token refresh scenarios.
@xingyaoww can click here to continue refining the PR
Agent Server images for this PR
• GHCR package: https://github.com/OpenHands/agent-sdk/pkgs/container/agent-server
Variants & Base Images
eclipse-temurin:17-jdknikolaik/python-nodejs:python3.13-nodejs22golang:1.21-bookwormPull (multi-arch manifest)
# Each variant is a multi-arch manifest supporting both amd64 and arm64 docker pull ghcr.io/openhands/agent-server:e8278f7-pythonRun
All tags pushed for this build
About Multi-Architecture Support
e8278f7-python) is a multi-arch manifest supporting both amd64 and arm64e8278f7-python-amd64) are also available if needed