Files

119 lines
5.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
name: openai-team-proxy
description: Set up, run, rotate, and debug OpenAI Team OAuth proxy — round-robin balancer for opencode/Hermes with 67+ accounts, auto-refresh, and billing diagnosis.
---
# OpenAI Team Proxy
Round-robin балансировщик OpenAI Team OAuth-аккаунтов. Прокси на `:20130`, совместим с OpenAI API (opencode, Kilo, Hermes, любой OpenAI-compatible клиент).
## Триггеры
- Пользователь прислал ZIP/JSON с team-аккаунтами OpenAI
- Нужно поднять прокси для opencode/Kilo/Hermes
- Ключи протухли — нужна ротация
- `billing_not_active` / `429` на team-аккаунтах
## Быстрый старт
```bash
cd openai-team
pip install -r requirements.txt
cp /path/to/batch.json current_batch.json
python -u proxy.py # -u обязательно на Windows для HTTP серверов
```
Проверка:
```bash
curl http://127.0.0.1:20130/health
# → {"status":"ok","accounts":67,"concurrency":670}
```
## Архитектура
- **proxy.py** — FastAPI + httpx, round-robin по аккаунтам, semaphore на concurrency
- **current_batch.json** — файл с OAuth-токенами (gitignore)
- **rotate.sh** — копирует новый батч + шлёт POST /reload
- Порт: `20130` (настраивается через `PORT` env)
- Прокси: `PROXY=socks5://user:pass@host:port` для исходящих
## Модели
Team-аккаунты дают доступ к: `gpt-5.2`, `gpt-5.3-codex`, `gpt-5.4`, `gpt-5.4-mini`, `gpt-5.5`, `gpt-5.6-luna`, `gpt-5.6-sol`, `gpt-5.6-terra`, `gpt-image-2`.
## Интеграция с opencode/Kilo
```jsonc
"openai_team": {
"npm": "@ai-sdk/openai-compatible",
"options": {
"baseURL": "http://127.0.0.1:20130/v1",
"apiKey": "sk-bypass"
},
"models": {
"gpt-5.6-terra": { "name": "gpt-5.6-terra" },
"gpt-5.4-mini": { "name": "gpt-5.4-mini" }
}
}
```
## Ротация ключей (~10 дней)
```bash
./rotate.sh /path/to/new_batch.json
# или вручную:
cp new.json current_batch.json && curl -X POST http://127.0.0.1:20130/reload
```
## Питфолы
### BILLING_NOT_ACTIVE (HTTP 429 body)
**ВСЕ 67 аккаунтов под одним workspace → биллинг общий.** Если workspace без карты — блокировка на всех. HTTP статус приходит 429, но тело содержит `billing_not_active`. Не путать с рейт-лимитом.
**Проверка:** прямой запрос к `https://api.openai.com/v1/chat/completions` с токеном и org_id. Если 429 + billing_not_active на нескольких раскиданных аккаунтах (напр. [0, 10, 20, 30, 40, 50, 60]) — проблема в workspace, не в отдельных токенах.
**Решение:** зайти в workspace на chatgpt.com → Billing → добавить карту.
### Refresh tokens — одноразовые
Refresh-токены в батче ОДНОРАЗОВЫЕ. После первого использования (`POST https://auth.openai.com/oauth/token`) — сгорают с ошибкой `refresh_token_reused`. Прокси использует их при 401, после чего полагается только на access_token.
### OAuth access_token — реальный JWT, не обрезан
В батчах `verify-jwt` access_token выглядит как `eyJhbG...bLiA` в read_file, но это артефакт отображения — реальный токен 1700+ символов, полный JWT. Проверять через `len(token)` в Python, не через read_file.
### Windows: python -u
На Windows HTTP-серверы в фоне需要通过 `python -u` (unbuffered). Без `-u` вывод буферизируется и сервер кажется мёртвым.
### concurrency = сумма
Каждый аккаунт имеет `concurrency: 10`. Общий semaphore = сумма всех concurrency (670 для 67 аккаунтов). Не путать с числом аккаунтов.
## Диагностика
```bash
# Статус
curl http://127.0.0.1:20130/health
# Модели
curl http://127.0.0.1:20130/v1/models
# Тестовый запрос
curl -s http://127.0.0.1:20130/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{"model":"gpt-5.4-mini","messages":[{"role":"user","content":"hi"}],"max_tokens":5}'
# Прямая проверка токенов (Python)
python -c "
import json, httpx, asyncio
async def test():
with open('current_batch.json') as f:
data = json.load(f)
for idx in [0, 10, 20, 30, 40, 50, 60, 66]:
a = data['accounts'][idx]
async with httpx.AsyncClient(timeout=30) as c:
r = await c.post('https://api.openai.com/v1/chat/completions',
headers={'Authorization': f'Bearer {a[\"credentials\"][\"access_token\"]}',
'OpenAI-Organization': a['credentials']['organization_id'],
'Content-Type': 'application/json'},
json={'model':'gpt-5.4-mini','messages':[{'role':'user','content':'hi'}],'max_tokens':5})
print(f'[{idx}] {a[\"name\"]:20s} | HTTP {r.status_code} | {r.json().get(\"error\",{}).get(\"message\",\"N/A\")}')
asyncio.run(test())
"
```