mirror of
https://github.com/katanemo/plano.git
synced 2026-04-25 00:36:34 +02:00
Add first-class ChatGPT subscription provider support (#881)
* Add first-class ChatGPT subscription provider support * Address PR feedback: move uuid import to top, reuse parsed config in up() * Add ChatGPT token watchdog for seamless long-lived sessions * Address PR feedback: error on stream=false for ChatGPT, fix auth file permissions * Replace ChatGPT watchdog/restart with passthrough_auth --------- Co-authored-by: Musa Malik <musam@uw.edu>
This commit is contained in:
parent
aa726b1bba
commit
78dc4edad9
18 changed files with 693 additions and 20 deletions
61
demos/llm_routing/chatgpt_subscription/README.md
Normal file
61
demos/llm_routing/chatgpt_subscription/README.md
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
# ChatGPT Subscription Routing
|
||||
|
||||
Route requests through your ChatGPT Plus/Pro subscription using Plano. Uses the OpenAI Responses API under the hood, targeting `chatgpt.com/backend-api/codex/responses`.
|
||||
|
||||
## Setup
|
||||
|
||||
### 1. Authenticate with ChatGPT
|
||||
|
||||
```bash
|
||||
planoai chatgpt login
|
||||
```
|
||||
|
||||
This opens a device code flow — visit the URL shown and enter the code. Tokens are saved to `~/.plano/chatgpt/auth.json`.
|
||||
|
||||
### 2. Start Plano
|
||||
|
||||
```bash
|
||||
planoai up config.yaml
|
||||
```
|
||||
|
||||
### 3. Send a request
|
||||
|
||||
```bash
|
||||
curl http://localhost:12000/v1/responses \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"model": "gpt-5.2",
|
||||
"input": "Hello, what model are you?"
|
||||
}'
|
||||
```
|
||||
|
||||
Or use the test script:
|
||||
|
||||
```bash
|
||||
bash test_chatgpt.sh
|
||||
```
|
||||
|
||||
## How it works
|
||||
|
||||
- `chatgpt/gpt-5.2` in the config tells Plano to use the ChatGPT subscription provider
|
||||
- Plano reads OAuth tokens from `~/.plano/chatgpt/auth.json` (auto-refreshes if expired)
|
||||
- Requests are proxied to `https://chatgpt.com/backend-api/codex/responses` with the required headers:
|
||||
- `Authorization: Bearer <access_token>`
|
||||
- `ChatGPT-Account-Id: <account_id>`
|
||||
- `originator: codex_cli_rs`
|
||||
- `session_id: <uuid>`
|
||||
|
||||
## Available models
|
||||
|
||||
```
|
||||
chatgpt/gpt-5.4
|
||||
chatgpt/gpt-5.3-codex
|
||||
chatgpt/gpt-5.2
|
||||
```
|
||||
|
||||
## Managing credentials
|
||||
|
||||
```bash
|
||||
planoai chatgpt status # Check auth status
|
||||
planoai chatgpt logout # Remove stored credentials
|
||||
```
|
||||
38
demos/llm_routing/chatgpt_subscription/chat.py
Normal file
38
demos/llm_routing/chatgpt_subscription/chat.py
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Interactive chat with a model through Plano using the OpenAI SDK."""
|
||||
|
||||
import sys
|
||||
from openai import OpenAI
|
||||
|
||||
client = OpenAI(base_url="http://localhost:12000/v1", api_key="unused")
|
||||
|
||||
|
||||
def run_chat(model):
|
||||
print(f"Chatting with {model} via Plano (Ctrl+C to quit)\n")
|
||||
history = []
|
||||
while True:
|
||||
try:
|
||||
user_input = input("you> ")
|
||||
except (KeyboardInterrupt, EOFError):
|
||||
print("\nbye")
|
||||
break
|
||||
if not user_input.strip():
|
||||
continue
|
||||
|
||||
history.append({"role": "user", "content": user_input})
|
||||
|
||||
stream = client.responses.create(model=model, input=history, stream=True)
|
||||
print(f"{model}> ", end="", flush=True)
|
||||
full = ""
|
||||
for event in stream:
|
||||
if event.type == "response.output_text.delta":
|
||||
print(event.delta, end="", flush=True)
|
||||
full += event.delta
|
||||
print()
|
||||
|
||||
history.append({"role": "assistant", "content": full})
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
model = sys.argv[1] if len(sys.argv) > 1 else "gpt-5.2"
|
||||
run_chat(model)
|
||||
9
demos/llm_routing/chatgpt_subscription/config.yaml
Normal file
9
demos/llm_routing/chatgpt_subscription/config.yaml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
version: v0.3.0
|
||||
|
||||
listeners:
|
||||
- type: model
|
||||
name: model_listener
|
||||
port: 12000
|
||||
|
||||
model_providers:
|
||||
- model: chatgpt/*
|
||||
18
demos/llm_routing/chatgpt_subscription/test_chatgpt.sh
Executable file
18
demos/llm_routing/chatgpt_subscription/test_chatgpt.sh
Executable file
|
|
@ -0,0 +1,18 @@
|
|||
#!/bin/bash
|
||||
# Test ChatGPT subscription routing through Plano
|
||||
# Prerequisites: planoai chatgpt login && planoai up config.yaml
|
||||
|
||||
set -e
|
||||
|
||||
echo "Testing ChatGPT subscription via Plano Responses API..."
|
||||
echo ""
|
||||
|
||||
curl -s http://localhost:12000/v1/responses \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"model": "gpt-5.2",
|
||||
"input": "What is 2 + 2? Reply in one word."
|
||||
}' | python3 -m json.tool
|
||||
|
||||
echo ""
|
||||
echo "Done."
|
||||
Loading…
Add table
Add a link
Reference in a new issue