fix: исправить падение claude_gpt (effort-proxy, гонка старта, xhigh→high)
Три корневые причины и исправления: 1. effort-proxy: однопоточный HTTPServer заменён на ThreadingMixIn, включён маппинг xhigh→high (claude-code-proxy больше не принимает xhigh), добавлено логирование ошибок в /tmp/claude-gpt-effort-proxy.log 2. Стартовая логика claude_gpt: убрано гоночное условие (pkill прокси при отсутствии effort-proxy), effort-proxy всегда перезапускается, curl -s вместо curl -sf для healthcheck'а 3. localhost заменён на 127.0.0.1 во всех URL для консистентности Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -105,29 +105,41 @@ else
|
|||||||
install_proxy
|
install_proxy
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# ── 4b. effort-proxy wrapper (маппинг effort для GPT: max->xhigh) ─────────
|
# ── 4b. effort-proxy wrapper (маппинг effort: xhigh→high) ─────────
|
||||||
EFFORT_PROXY_BIN="$BIN_DIR/claude-gpt-effort-proxy.py"
|
EFFORT_PROXY_BIN="$BIN_DIR/claude-gpt-effort-proxy.py"
|
||||||
cat > "$EFFORT_PROXY_BIN" << 'PYEOF'
|
cat > "$EFFORT_PROXY_BIN" << 'PYEOF'
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""Effort mapping proxy for GPT backend.
|
"""Effort mapping proxy for GPT backend.
|
||||||
|
|
||||||
GPT-5.5 natively supports: low, medium, high, xhigh (no "max").
|
claude-code-proxy now accepts: low, medium, high, max (no "xhigh").
|
||||||
Claude Code may send "max" effort — we map it to "xhigh" (highest GPT level).
|
Claude Code may send "xhigh" effort — we map it to "high".
|
||||||
See EFFORT_MAPPING.md for the full mapping table across all providers.
|
|
||||||
"""
|
"""
|
||||||
import http.client, http.server, sys
|
import http.client, http.server, sys, logging, socketserver
|
||||||
|
|
||||||
UPSTREAM_PORT = int(sys.argv[1]) if len(sys.argv) > 1 else 18766
|
UPSTREAM_PORT = int(sys.argv[1]) if len(sys.argv) > 1 else 18766
|
||||||
LISTEN_PORT = int(sys.argv[2]) if len(sys.argv) > 2 else 18765
|
LISTEN_PORT = int(sys.argv[2]) if len(sys.argv) > 2 else 18765
|
||||||
|
|
||||||
|
logging.basicConfig(
|
||||||
|
filename="/tmp/claude-gpt-effort-proxy.log",
|
||||||
|
level=logging.INFO,
|
||||||
|
format='{"t":"%(asctime)s","level":"%(levelname)s","msg":"%(message)s"}',
|
||||||
|
datefmt='%Y-%m-%dT%H:%M:%S',
|
||||||
|
)
|
||||||
|
log = logging.getLogger("effort-proxy")
|
||||||
|
|
||||||
|
# Потокобезопасный сервер — обрабатывает несколько запросов одновременно
|
||||||
|
class _ThreadedServer(socketserver.ThreadingMixIn, http.server.HTTPServer):
|
||||||
|
daemon_threads = True
|
||||||
|
|
||||||
class _Proxy(http.server.BaseHTTPRequestHandler):
|
class _Proxy(http.server.BaseHTTPRequestHandler):
|
||||||
def proxy_request(self):
|
def proxy_request(self):
|
||||||
body = b""
|
body = b""
|
||||||
if cl := self.headers.get("Content-Length"):
|
if cl := self.headers.get("Content-Length"):
|
||||||
body = self.rfile.read(int(cl))
|
body = self.rfile.read(int(cl))
|
||||||
body = body.replace(b'"max"', b'"xhigh"')
|
# Маппинг xhigh→high: claude-code-proxy больше не принимает xhigh
|
||||||
|
body = body.replace(b'"xhigh"', b'"high"')
|
||||||
try:
|
try:
|
||||||
conn = http.client.HTTPConnection("localhost", UPSTREAM_PORT, timeout=300)
|
conn = http.client.HTTPConnection("127.0.0.1", UPSTREAM_PORT, timeout=300)
|
||||||
hdrs = dict(self.headers)
|
hdrs = dict(self.headers)
|
||||||
hdrs.pop("Host", None)
|
hdrs.pop("Host", None)
|
||||||
hdrs["Content-Length"] = str(len(body))
|
hdrs["Content-Length"] = str(len(body))
|
||||||
@@ -154,12 +166,14 @@ class _Proxy(http.server.BaseHTTPRequestHandler):
|
|||||||
except: pass
|
except: pass
|
||||||
conn.close()
|
conn.close()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
log.error("proxy error: %s", e)
|
||||||
try: self.send_error(502, str(e))
|
try: self.send_error(502, str(e))
|
||||||
except: pass
|
except: pass
|
||||||
do_GET = do_POST = do_PUT = do_DELETE = do_HEAD = proxy_request
|
do_GET = do_POST = do_PUT = do_DELETE = do_HEAD = proxy_request
|
||||||
def log_message(self, *args): pass
|
def log_message(self, *args): pass
|
||||||
|
|
||||||
http.server.HTTPServer(("localhost", LISTEN_PORT), _Proxy).serve_forever()
|
log.info("effort-proxy starting on 127.0.0.1:%d → upstream %d", LISTEN_PORT, UPSTREAM_PORT)
|
||||||
|
_ThreadedServer(("127.0.0.1", LISTEN_PORT), _Proxy).serve_forever()
|
||||||
PYEOF
|
PYEOF
|
||||||
chmod +x "$EFFORT_PROXY_BIN"
|
chmod +x "$EFFORT_PROXY_BIN"
|
||||||
success "claude-gpt-effort-proxy -> $EFFORT_PROXY_BIN"
|
success "claude-gpt-effort-proxy -> $EFFORT_PROXY_BIN"
|
||||||
@@ -367,26 +381,34 @@ cleanup() {
|
|||||||
}
|
}
|
||||||
trap cleanup EXIT INT TERM
|
trap cleanup EXIT INT TERM
|
||||||
|
|
||||||
if pgrep -f "claude-code-proxy serve" &>/dev/null && ! pgrep -f "claude-gpt-effort-proxy" &>/dev/null; then
|
# Всегда принудительно убираем старый effort-proxy (может висеть после краша)
|
||||||
pkill -f "claude-code-proxy serve" 2>/dev/null
|
pkill -f "claude-gpt-effort-proxy" 2>/dev/null
|
||||||
sleep 0.5
|
sleep 0.3
|
||||||
fi
|
|
||||||
|
|
||||||
|
# Запускаем claude-code-proxy если не запущен
|
||||||
if ! pgrep -f "claude-code-proxy serve" &>/dev/null; then
|
if ! pgrep -f "claude-code-proxy serve" &>/dev/null; then
|
||||||
PORT=18766 "$proxy_bin" serve &>/tmp/claude-code-proxy.log &
|
PORT=18766 "$proxy_bin" serve &>/tmp/claude-code-proxy.log &
|
||||||
proxy_pid=$!
|
proxy_pid=$!
|
||||||
_j=0; while [ $_j -lt 10 ]; do sleep 1; curl -sf --max-time 1 http://localhost:18766/ &>/dev/null; [ "$?" -ne 7 ] && break; _j=$((_j + 1)); done
|
_j=0; while [ $_j -lt 10 ]; do sleep 1; curl -s --max-time 1 http://127.0.0.1:18766/ &>/dev/null; [ "$?" -ne 7 ] && break; _j=$((_j + 1)); done
|
||||||
|
if [ $_j -ge 10 ]; then
|
||||||
|
echo -e "\033[0;31m[ОШИБКА]\033[0m claude-code-proxy не запустился за 10 сек."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! pgrep -f "claude-gpt-effort-proxy" &>/dev/null; then
|
# Запускаем effort-proxy (всегда свежий экземпляр)
|
||||||
python3 "$effort_proxy" 18766 18765 &>/tmp/claude-gpt-effort-proxy.log &
|
python3 "$effort_proxy" 18766 18765 &>/tmp/claude-gpt-effort-proxy.log &
|
||||||
wrapper_pid=$!
|
wrapper_pid=$!
|
||||||
_i=0; while [ $_i -lt 10 ]; do sleep 1; curl -sf --max-time 1 http://localhost:18765/ &>/dev/null; [ "$?" -ne 7 ] && break; # exit 7 = connection refused
|
_i=0; while [ $_i -lt 10 ]; do sleep 1; curl -s --max-time 1 http://127.0.0.1:18765/ &>/dev/null; [ "$?" -ne 7 ] && break; _i=$((_i + 1)); done
|
||||||
_i=$((_i + 1)); done
|
if [ $_i -ge 10 ]; then
|
||||||
|
echo -e "\033[0;31m[ОШИБКА]\033[0m claude-gpt-effort-proxy не запустился за 10 сек."
|
||||||
|
echo "Лог effort-proxy:"
|
||||||
|
cat /tmp/claude-gpt-effort-proxy.log 2>/dev/null
|
||||||
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo -n "Проверка авторизации ChatGPT... "
|
echo -n "Проверка авторизации ChatGPT... "
|
||||||
_claude_test_api "http://localhost:18765/v1/messages" "x-api-key: dummy" "gpt-5.4-mini"
|
_claude_test_api "http://127.0.0.1:18765/v1/messages" "x-api-key: dummy" "gpt-5.4-mini"
|
||||||
|
|
||||||
if [ "$_CLAUDE_TEST_CODE" != "400" ]; then
|
if [ "$_CLAUDE_TEST_CODE" != "400" ]; then
|
||||||
_handle_api_response "ChatGPT" "$_CLAUDE_TEST_CODE" "$_CLAUDE_TEST_BODY" ""
|
_handle_api_response "ChatGPT" "$_CLAUDE_TEST_CODE" "$_CLAUDE_TEST_BODY" ""
|
||||||
@@ -395,7 +417,7 @@ if [ "$_CLAUDE_TEST_CODE" != "400" ]; then
|
|||||||
"$proxy_bin" codex auth logout 2>/dev/null
|
"$proxy_bin" codex auth logout 2>/dev/null
|
||||||
if _claude_offer_reauth "ChatGPT"; then
|
if _claude_offer_reauth "ChatGPT"; then
|
||||||
"$proxy_bin" codex auth login || exit 1
|
"$proxy_bin" codex auth login || exit 1
|
||||||
_claude_test_api "http://localhost:18765/v1/messages" "x-api-key: dummy" "gpt-5.4-mini"
|
_claude_test_api "http://127.0.0.1:18765/v1/messages" "x-api-key: dummy" "gpt-5.4-mini"
|
||||||
[ "$_CLAUDE_TEST_CODE" != "200" ] && [ "$_CLAUDE_TEST_CODE" != "400" ] && { echo "ОШИБКА"; exit 1; }
|
[ "$_CLAUDE_TEST_CODE" != "200" ] && [ "$_CLAUDE_TEST_CODE" != "400" ] && { echo "ОШИБКА"; exit 1; }
|
||||||
echo -e "\033[0;32mOK\033[0m"
|
echo -e "\033[0;32mOK\033[0m"
|
||||||
else
|
else
|
||||||
@@ -416,7 +438,7 @@ echo -e "\033[0;33m[ИНФО]\033[0m Режим ChatGPT. Для выхода: Ct
|
|||||||
echo -e " Команда \033[1m/logout\033[0m выйдет из Anthropic, а не из ChatGPT."
|
echo -e " Команда \033[1m/logout\033[0m выйдет из Anthropic, а не из ChatGPT."
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
ANTHROPIC_BASE_URL=http://localhost:18765 \
|
ANTHROPIC_BASE_URL=http://127.0.0.1:18765 \
|
||||||
ANTHROPIC_AUTH_TOKEN=dummy \
|
ANTHROPIC_AUTH_TOKEN=dummy \
|
||||||
ANTHROPIC_MODEL=gpt-5.5 \
|
ANTHROPIC_MODEL=gpt-5.5 \
|
||||||
ANTHROPIC_DEFAULT_OPUS_MODEL=gpt-5.5 \
|
ANTHROPIC_DEFAULT_OPUS_MODEL=gpt-5.5 \
|
||||||
|
|||||||
Reference in New Issue
Block a user