Metadata-Version: 2.4
Name: algocean-codex-oauth
Version: 0.2.3
Summary: Drop-in ChatOpenAI replacement for LangChain/LangGraph — local Codex OAuth or deployed OpenAI API key.
Project-URL: Homepage, https://github.com/algocean1204/AlgoceanCodexOAuth
Project-URL: Documentation, https://github.com/algocean1204/AlgoceanCodexOAuth#readme
Project-URL: Repository, https://github.com/algocean1204/AlgoceanCodexOAuth
Project-URL: Issues, https://github.com/algocean1204/AlgoceanCodexOAuth/issues
Project-URL: Changelog, https://github.com/algocean1204/AlgoceanCodexOAuth/releases
Author: algocean1204
License-Expression: MIT
License-File: LICENSE
Keywords: algocean,chatgpt,codex,langchain,langgraph,oauth,openai
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.10
Requires-Dist: langchain-core>=0.3.0
Provides-Extra: dev
Requires-Dist: langchain-openai>=0.2.0; extra == 'dev'
Requires-Dist: pydantic>=2.0; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Provides-Extra: openai
Requires-Dist: langchain-openai>=0.2.0; extra == 'openai'
Description-Content-Type: text/markdown

# AlgoceanCodexOAuth

LangChain / LangGraph에서 **`ChatOpenAI` 자리에 그대로 꽂는** LLM 래퍼입니다.

`auth=oauth`면 로컬 Codex CLI + ChatGPT OAuth 구독 한도를, `auth=api_key`면 OpenAI API key 과금 경로를 사용합니다.

```text
LangGraph / LangChain
  → AlgoceanCodexOAuth(auth=oauth | api_key)
  → oauth: codex exec → 로컬 ChatGPT OAuth
  → api_key: langchain_openai.ChatOpenAI 위임
```

## 설치

### Local — Codex OAuth (개발 PC)

```bash
npm install -g @openai/codex

unset OPENAI_API_KEY
unset CODEX_API_KEY
codex logout
codex login
codex login status
```

공식 인증 문서: [Codex Authentication](https://developers.openai.com/codex/auth)

```bash
pip install algocean-codex-oauth
```

### Production — OpenAI API key (배포 서버)

```bash
pip install "algocean-codex-oauth[openai]"
```

`.env` 또는 환경 변수:

```bash
export ALGOCEANCODEXOAUTH_API=sk-...
# 선택: ALGOCEANCODEXOAUTH_AUTH=api_key  (기본값 oauth)
```

LangGraph 프로젝트:

```bash
pip install "algocean-codex-oauth[openai]" langgraph langchain-core
```

## Quick Start

### Local (OAuth — 기본)

```python
from algocean_codex_oauth import AlgoceanCodexOAuth, oauth
from langchain_core.messages import HumanMessage

llm = AlgoceanCodexOAuth(auth=oauth, model="gpt-5.5")
# auth 생략 시 oauth가 기본값
response = llm.invoke([HumanMessage(content="FastAPI Depends를 짧게 설명해줘.")])
print(response.content)
```

### Production (API key)

```python
from algocean_codex_oauth import AlgoceanCodexOAuth, api_key
from langchain_core.messages import HumanMessage

llm = AlgoceanCodexOAuth(auth=api_key, model="gpt-4o")
response = llm.invoke([HumanMessage(content="FastAPI Depends를 짧게 설명해줘.")])
print(response.content)
```

환경 변수로 모드 선택:

```python
from algocean_codex_oauth import AlgoceanCodexOAuth

llm = AlgoceanCodexOAuth.from_env(model="gpt-4o")
```

`from_env()`는 `ALGOCEANCODEXOAUTH_AUTH=api_key`일 때 `ALGOCEANCODEXOAUTH_API`가 필요합니다.

### 터미널 가이드 — `help()`

```python
from algocean_codex_oauth import AlgoceanCodexOAuth

AlgoceanCodexOAuth.help()                  # 개요
AlgoceanCodexOAuth.help("langgraph")       # LangGraph 사용법
AlgoceanCodexOAuth.help("auth")            # oauth vs api_key
AlgoceanCodexOAuth.help("all")             # 전체 가이드
```

토픽: `install`, `quickstart`, `langgraph`, `auth`, `multiturn`, `presets`, `all`

## auth 모드 비교


|                            | `auth=oauth` (기본)             | `auth=api_key`                  |
| -------------------------- | ----------------------------- | ------------------------------- |
| 용도                         | 로컬 개발, Codex 구독               | 배포 서버, OpenAI 과금                |
| 인증                         | `codex login` (ChatGPT OAuth) | `ALGOCEANCODEXOAUTH_API=sk-...` |
| 백엔드                        | `codex exec`                  | `langchain_openai.ChatOpenAI`   |
| `repo_read` / `repo_write` | 지원                            | **미지원** (oauth 전용)              |
| `thread_mode=codex_resume` | 지원                            | **미지원**                         |
| OAuth 모드 API key 차단        | `OPENAI_API_KEY` 등 제거         | 해당 없음                           |
| `workdir=None` (LangGraph Q&A) | **LLM-only 고정**: AGENTS.md 무시 + chat preamble + read-only | 해당 없음 |


## LangGraph

### 단일 노드 (OAuth)

```python
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")  # auth=oauth 기본

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()
```

### 배포용 — API key로 동일 그래프

```python
from algocean_codex_oauth import AlgoceanCodexOAuth, api_key

llm = AlgoceanCodexOAuth(auth=api_key, model="gpt-4o")
# 그래프 코드는 import / auth / model만 바꾸면 동일
```

### ReAct Agent

```python
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

```python
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)
```

- **oauth**: Codex CLI `--output-schema` 사용
- **api_key**: `ChatOpenAI.with_structured_output` 위임

## ChatOpenAI 기능 대응


| ChatOpenAI                            | AlgoceanCodexOAuth                              |
| ------------------------------------- | ----------------------------------------------- |
| `llm.invoke(messages)`                | 동일                                              |
| `await llm.ainvoke(messages)`         | 동일                                              |
| `llm.astream(messages)`               | 동일                                              |
| `llm.with_structured_output(schema)`  | 동일                                              |
| LangGraph `state["messages"]` 멀티턴     | `thread_mode="messages"` (기본, oauth/api_key 공통) |
| Codex thread resume                   | `thread_mode="codex_resume"` (**oauth 전용**)     |
| 새 대화 시작                               | `llm.reset_thread()` (oauth)                    |
| `response.response_metadata["usage"]` | oauth: Codex usage / api_key: OpenAI usage      |


## 생성자

```python
from algocean_codex_oauth import AlgoceanCodexOAuth, oauth, api_key

AlgoceanCodexOAuth(
    model: str = "gpt-5.5",
    auth: str = oauth,              # oauth | api_key
    timeout: int = 180,
    sandbox: str = "read-only",     # oauth 전용
    workdir: str | None = None,     # oauth 전용
    ephemeral: bool = True,         # oauth 전용
    thread_mode: str = "messages",  # messages | codex_resume (oauth)
    codex_bin: str = "codex",
    require_chatgpt_login: bool = True,
)
```

### Preset (oauth 전용)

```python
llm = AlgoceanCodexOAuth.chat(model="gpt-5.5")
llm = AlgoceanCodexOAuth.repo_read(workdir="/path/to/repo")
llm = AlgoceanCodexOAuth.repo_write(workdir="/path/to/repo")
```


| Preset             | auth       | thread_mode    |
| ------------------ | ---------- | -------------- |
| `chat()`           | oauth (기본) | `messages`     |
| `repo_read(path)`  | oauth 필수   | `messages`     |
| `repo_write(path)` | oauth 필수   | `codex_resume` |


## 환경 변수


| 변수                        | 용도                                    |
| ------------------------- | ------------------------------------- |
| `ALGOCEANCODEXOAUTH_API`  | `auth=api_key` 시 OpenAI API key (필수)  |
| `ALGOCEANCODEXOAUTH_AUTH` | `oauth` 또는 `api_key` (선택, 기본 `oauth`) |


## 멀티턴 — ChatOpenAI와 동일하게 (messages 모드)

```python
messages = [HumanMessage(content="코드네임은 ALPHA7")]
ai1 = await llm.ainvoke(messages)
messages += [ai1, HumanMessage(content="코드네임이 뭐야?")]
ai2 = await llm.ainvoke(messages)
```

LangGraph `state["messages"]` 패턴과 1:1 동일합니다. oauth / api_key 모두 동일.

### codex_resume (oauth 전용)

```python
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="이어서")])
llm.reset_thread()
```

### Streaming

```python
async for chunk in llm.astream([HumanMessage(content="hello")]):
    print(chunk.content, end="", flush=True)
```

## Local / Production 스위치

```python
import os
from algocean_codex_oauth import AlgoceanCodexOAuth, oauth, api_key

def get_llm():
    if os.getenv("ALGOCEANCODEXOAUTH_API"):
        return AlgoceanCodexOAuth(auth=api_key, model="gpt-4o")
    return AlgoceanCodexOAuth(auth=oauth, model="gpt-5.5")
```

그래프 코드는 동일하고 `auth` / `model`만 바꾸면 됩니다.

## OAuth 정책 (auth=oauth)

라이브러리는 oauth 호출마다 아래를 강제합니다.

- `OPENAI_API_KEY`, `CODEX_API_KEY` 환경 변수 제거
- `require_chatgpt_login=True` 시 `codex login status`로 ChatGPT OAuth 확인
- API key 인증 감지 시 `AlgoceanCodexOAuthError` 발생

## 아키텍처

```text
algocean_codex_oauth/
├── chat_model.py    # AlgoceanCodexOAuth — oauth / api_key 라우팅
├── auth_mode.py     # oauth, api_key 상수 + env 로더
├── client.py        # codex exec / exec resume (oauth)
├── auth.py          # OAuth 검증, API key 차단 (oauth)
├── config.py
├── messages.py
├── session.py       # codex_resume 편의 (oauth)
└── errors.py
```

## 멀티턴 (Session 래퍼, oauth 전용)

`AlgoceanCodexSession`은 `thread_mode="codex_resume"` 편의 래퍼입니다.

## 제한

- **oauth**: 개인 로컬 / 개인 구독 용도. SaaS 서버에 부적합.
- **api_key**: OpenAI API key 과금. repo sandbox / codex resume 미지원.
- oauth 모드: Codex CLI(`codex`)가 PATH에 있어야 합니다.

## 개발

```bash
git clone https://github.com/algocean1204/AlgoceanCodexOAuth.git
cd AlgoceanCodexOAuth
pip install -e ".[dev]"
pytest
```

통합 테스트 (별도 폴더):

```bash
cd ../AlgoceanCodexOAuth_IntegrationTest
pip install -e ../AlgoceanCodexOAuth/.[dev] langgraph
python run_all_tests.py --mode mock
```

## PyPI

```bash
pip install algocean-codex-oauth
pip install "algocean-codex-oauth[openai]"   # api_key 모드
```

## License

MIT

## Links

- GitHub: [https://github.com/algocean1204/AlgoceanCodexOAuth](https://github.com/algocean1204/AlgoceanCodexOAuth)
- Codex CLI: [https://developers.openai.com/codex/cli/reference](https://developers.openai.com/codex/cli/reference)
- Codex Auth: [https://developers.openai.com/codex/auth](https://developers.openai.com/codex/auth)

