From a1bf8023a9f9a3e4d3063f51120db12dd591061a Mon Sep 17 00:00:00 2001 From: vitaly Date: Sun, 31 May 2026 15:55:38 +0700 Subject: [PATCH] =?UTF-8?q?fix:=20=D0=B8=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20=D0=BF=D0=B0=D0=B4=D0=B5=D0=BD=D0=B8=D0=B5?= =?UTF-8?q?=20claude=5Fgpt=20(effort-proxy,=20=D0=B3=D0=BE=D0=BD=D0=BA?= =?UTF-8?q?=D0=B0=20=D1=81=D1=82=D0=B0=D1=80=D1=82=D0=B0,=20xhigh=E2=86=92?= =?UTF-8?q?high)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Три корневые причины и исправления: 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 --- claude_setup.sh | 64 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 43 insertions(+), 21 deletions(-) diff --git a/claude_setup.sh b/claude_setup.sh index 355d2c8..e7da12a 100755 --- a/claude_setup.sh +++ b/claude_setup.sh @@ -105,29 +105,41 @@ else install_proxy 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" cat > "$EFFORT_PROXY_BIN" << 'PYEOF' #!/usr/bin/env python3 """Effort mapping proxy for GPT backend. -GPT-5.5 natively supports: low, medium, high, xhigh (no "max"). -Claude Code may send "max" effort — we map it to "xhigh" (highest GPT level). -See EFFORT_MAPPING.md for the full mapping table across all providers. +claude-code-proxy now accepts: low, medium, high, max (no "xhigh"). +Claude Code may send "xhigh" effort — we map it to "high". """ -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 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): def proxy_request(self): body = b"" if cl := self.headers.get("Content-Length"): 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: - 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.pop("Host", None) hdrs["Content-Length"] = str(len(body)) @@ -154,12 +166,14 @@ class _Proxy(http.server.BaseHTTPRequestHandler): except: pass conn.close() except Exception as e: + log.error("proxy error: %s", e) try: self.send_error(502, str(e)) except: pass do_GET = do_POST = do_PUT = do_DELETE = do_HEAD = proxy_request 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 chmod +x "$EFFORT_PROXY_BIN" success "claude-gpt-effort-proxy -> $EFFORT_PROXY_BIN" @@ -367,26 +381,34 @@ cleanup() { } trap cleanup EXIT INT TERM -if pgrep -f "claude-code-proxy serve" &>/dev/null && ! pgrep -f "claude-gpt-effort-proxy" &>/dev/null; then - pkill -f "claude-code-proxy serve" 2>/dev/null - sleep 0.5 -fi +# Всегда принудительно убираем старый effort-proxy (может висеть после краша) +pkill -f "claude-gpt-effort-proxy" 2>/dev/null +sleep 0.3 +# Запускаем claude-code-proxy если не запущен if ! pgrep -f "claude-code-proxy serve" &>/dev/null; then PORT=18766 "$proxy_bin" serve &>/tmp/claude-code-proxy.log & 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 -if ! pgrep -f "claude-gpt-effort-proxy" &>/dev/null; then - python3 "$effort_proxy" 18766 18765 &>/tmp/claude-gpt-effort-proxy.log & - 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=$((_i + 1)); done +# Запускаем effort-proxy (всегда свежий экземпляр) +python3 "$effort_proxy" 18766 18765 &>/tmp/claude-gpt-effort-proxy.log & +wrapper_pid=$! +_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 +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 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 _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 if _claude_offer_reauth "ChatGPT"; then "$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; } echo -e "\033[0;32mOK\033[0m" else @@ -416,7 +438,7 @@ echo -e "\033[0;33m[ИНФО]\033[0m Режим ChatGPT. Для выхода: Ct echo -e " Команда \033[1m/logout\033[0m выйдет из Anthropic, а не из ChatGPT." echo "" -ANTHROPIC_BASE_URL=http://localhost:18765 \ +ANTHROPIC_BASE_URL=http://127.0.0.1:18765 \ ANTHROPIC_AUTH_TOKEN=dummy \ ANTHROPIC_MODEL=gpt-5.5 \ ANTHROPIC_DEFAULT_OPUS_MODEL=gpt-5.5 \