Files
autoreg-skills-max/skills/openai-team-proxy/SKILL.md

5.4 KiB
Raw Blame History

name, description
name description
openai-team-proxy 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-аккаунтах

Быстрый старт

cd openai-team
pip install -r requirements.txt
cp /path/to/batch.json current_batch.json
python -u proxy.py   # -u обязательно на Windows для HTTP серверов

Проверка:

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

"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 дней)

./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 аккаунтов). Не путать с числом аккаунтов.

Диагностика

# Статус
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())
"