Drop-in ChatOpenAI replacement for LangChain/LangGraph using Codex ChatGPT OAuth subscription.
Project description
AlgoceanCodexOAuth
LangChain / LangGraph에서 ChatOpenAI 자리에 그대로 꽂는 Codex ChatGPT OAuth LLM 래퍼입니다.
API key 과금 경로는 코드에서 차단하고, 로컬 codex login으로 저장된 ChatGPT OAuth 구독 한도만 사용합니다.
LangGraph / LangChain
→ AlgoceanCodexOAuth
→ codex exec
→ 로컬 ChatGPT OAuth 세션
→ Codex 구독 한도 / 크레딧
설치
1. Codex CLI + ChatGPT OAuth (1회)
npm install -g @openai/codex
unset OPENAI_API_KEY
unset CODEX_API_KEY
codex logout
codex login
codex login status
공식 인증 문서: Codex Authentication
2. Python 패키지
pip install algocean-codex-oauth
LangGraph 프로젝트:
pip install algocean-codex-oauth langgraph langchain-core
Quick Start
ChatOpenAI → AlgoceanCodexOAuth (1:1 교체)
Before (API key)
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage
llm = ChatOpenAI(model="gpt-4o")
response = llm.invoke([HumanMessage(content="FastAPI Depends를 짧게 설명해줘.")])
print(response.content)
After (Codex OAuth)
from algocean_codex_oauth import AlgoceanCodexOAuth
from langchain_core.messages import HumanMessage
llm = AlgoceanCodexOAuth(model="gpt-5.5")
response = llm.invoke([HumanMessage(content="FastAPI Depends를 짧게 설명해줘.")])
print(response.content)
LangGraph
단일 노드
from langchain_core.messages import HumanMessage, SystemMessage
from langgraph.graph import StateGraph, END
from typing_extensions import TypedDict
from algocean_codex_oauth import AlgoceanCodexOAuth
class State(TypedDict):
user_input: str
answer: str
llm = AlgoceanCodexOAuth(model="gpt-5.5")
async def assistant_node(state: State) -> State:
messages = [
SystemMessage(content="간결한 개인 비서."),
HumanMessage(content=state["user_input"]),
]
ai = await llm.ainvoke(messages)
return {"answer": ai.content}
graph = StateGraph(State)
graph.add_node("assistant", assistant_node)
graph.set_entry_point("assistant")
graph.add_edge("assistant", END)
app = graph.compile()
ReAct Agent
from langgraph.prebuilt import create_react_agent
from langchain_core.messages import HumanMessage
from algocean_codex_oauth import AlgoceanCodexOAuth
llm = AlgoceanCodexOAuth(model="gpt-5.5")
agent = create_react_agent(llm, tools=[])
result = agent.invoke({"messages": [HumanMessage(content="hello")]})
Structured Output (LangGraph state merge)
from pydantic import BaseModel, Field
from langchain_core.messages import HumanMessage
from algocean_codex_oauth import AlgoceanCodexOAuth
class Analysis(BaseModel):
summary: str = Field(description="요약")
risk_level: str = Field(description="low | medium | high")
llm = AlgoceanCodexOAuth(model="gpt-5.5")
structured = llm.with_structured_output(Analysis)
result = structured.invoke([HumanMessage(content="위험도를 평가해줘.")])
print(result.summary, result.risk_level)
내부적으로 Codex CLI --output-schema를 사용합니다.
문서: Codex non-interactive mode
ChatOpenAI 기능 대응
| ChatOpenAI (API key) | AlgoceanCodexOAuth |
|---|---|
llm.invoke(messages) |
동일 |
await llm.ainvoke(messages) |
동일 |
llm.astream(messages) |
동일 |
llm.with_structured_output(schema) |
동일 |
LangGraph state["messages"] 멀티턴 |
thread_mode="messages" (기본) |
| 대화 세션 유지 | thread_mode="codex_resume" + ephemeral=False |
| 새 대화 시작 | llm.reset_thread() |
response.response_metadata["usage"] |
동일 |
생성자
AlgoceanCodexOAuth(
model: str = "gpt-5.5",
*,
timeout: int = 180,
sandbox: str = "read-only",
workdir: str | None = None,
ephemeral: bool = True,
thread_mode: str = "messages", # messages | codex_resume
codex_bin: str = "codex",
require_chatgpt_login: bool = True,
)
Preset
llm = AlgoceanCodexOAuth.chat(model="gpt-5.5") # messages 멀티턴
llm = AlgoceanCodexOAuth.repo_read(workdir="/path/to/repo")
llm = AlgoceanCodexOAuth.repo_write(workdir="/path/to/repo") # codex_resume
| Preset | thread_mode | 멀티턴 방식 |
|---|---|---|
chat() |
messages |
ChatOpenAI처럼 messages 히스토리 전달 |
repo_read(path) |
messages |
messages 히스토리 |
repo_write(path) |
codex_resume |
Codex exec resume (에이전트) |
멀티턴 — ChatOpenAI와 동일하게
방식 1: messages (기본, LangGraph 표준)
messages = [HumanMessage(content="코드네임은 ALPHA7")]
ai1 = await llm.ainvoke(messages)
messages += [ai1, HumanMessage(content="코드네임이 뭐야?")]
ai2 = await llm.ainvoke(messages)
LangGraph state["messages"] 패턴과 1:1 동일합니다.
방식 2: codex_resume (Codex thread 유지)
llm = AlgoceanCodexOAuth(
model="gpt-5.5",
workdir="/path/to/repo",
sandbox="read-only",
ephemeral=False,
thread_mode="codex_resume",
)
await llm.ainvoke([HumanMessage(content="첫 질문")])
await llm.ainvoke([HumanMessage(content="이어서")]) # exec resume
llm.reset_thread() # 새 대화
Streaming
async for chunk in llm.astream([HumanMessage(content="hello")]):
print(chunk.content, end="", flush=True)
Provider 스위치 (미니 Codex)
def get_llm(use_codex_oauth: bool):
if use_codex_oauth:
from algocean_codex_oauth import AlgoceanCodexOAuth
return AlgoceanCodexOAuth(model="gpt-5.5")
from langchain_openai import ChatOpenAI
return ChatOpenAI(model="gpt-4o")
그래프 코드는 동일하고 import / 클래스만 바꾸면 됩니다.
OAuth 정책
라이브러리는 호출마다 아래를 강제합니다.
OPENAI_API_KEY,CODEX_API_KEY환경 변수 제거require_chatgpt_login=True시codex login status로 ChatGPT OAuth 확인- API key 인증 감지 시
AlgoceanCodexOAuthError발생
아키텍처
algocean_codex_oauth/
├── chat_model.py # AlgoceanCodexOAuth (BaseChatModel) — public API
├── client.py # codex exec / exec resume
├── auth.py # OAuth 검증, API key 차단
├── config.py # AlgoceanCodexConfig
├── messages.py # LangChain messages → prompt
├── session.py # 멀티턴 thread resume (고급)
└── errors.py
멀티턴 (Session 래퍼)
AlgoceanCodexSession은 thread_mode="codex_resume" 편의 래퍼입니다.
직접 AlgoceanCodexOAuth(..., thread_mode="codex_resume") 를 써도 동일합니다.
제한
- 개인 로컬 / 개인 구독 용도입니다. SaaS 서버에서 외부 사용자에게 AI를 제공하는 용도에는 맞지 않습니다.
- Codex CLI(
codex)가 PATH에 있어야 합니다. danger-full-accesssandbox는 격리 환경에서만 사용하세요.
개발
git clone https://github.com/algocean1204/AlgoceanCodexOAuth.git
cd AlgoceanCodexOAuth
pip install -e ".[dev]"
pytest
PyPI
pip install algocean-codex-oauth
License
MIT
Links
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file algocean_codex_oauth-0.1.0.tar.gz.
File metadata
- Download URL: algocean_codex_oauth-0.1.0.tar.gz
- Upload date:
- Size: 11.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
101f73ee9bf9c5f7b581a5e2b44420b4876dc72e6fb8562b2b0838b51f8042c3
|
|
| MD5 |
f691a0768e635c1e28fefaddd320c3c0
|
|
| BLAKE2b-256 |
ecb2baa3f9fdb3738f44eb2bab6cd07f03e09874f8d89903c9cc687e0babfbfc
|
File details
Details for the file algocean_codex_oauth-0.1.0-py3-none-any.whl.
File metadata
- Download URL: algocean_codex_oauth-0.1.0-py3-none-any.whl
- Upload date:
- Size: 14.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2dda47950c62a8c99d6e9a0a9aae485d5b853e2bb55eab21e964e0dd98ff3c5d
|
|
| MD5 |
4bc22d2f85985288279d5ca07e7be553
|
|
| BLAKE2b-256 |
c0196a71a6771ff52b819bb8fa86c0bbe09938c600f152f38ce3ab4cc8ee66d5
|