feat(eltex): add ai-eltex launcher for corporate LLM proxy
ai-eltex runs Claude Code through the Eltex LiteLLM proxy (http://llm.eltex.loc:4000, team GLM subscription). The personal key from admins is checked via /v1/models and stored in ~/.config/ai-setup/eltex_key; the model is taken from the key's allowed list (ELTEX_MODEL / ELTEX_BASE_URL override). The proxy ignores effort/thinking, so no effort forcing. /logout-eltex and /logout in ai-eltex drop the key; setup.sh status shows it. ru-bypass: hosts block now has an end marker and only that block is rewritten, manual entries outside it survive; llm.eltex.loc/llm2 added since the VPN DNS does not resolve it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
# Copyright (c) 2026 Виталий Никитенко. MIT License.
|
||||
# ============================================================
|
||||
# AI Setup - Claude / GPT-5.5 / Grok / Qwen / DeepSeek / Kimi / GLM / Gemini
|
||||
# AI Setup - Claude / GPT-5.5 / Grok / Qwen / DeepSeek / Kimi / GLM / Eltex / Gemini
|
||||
# Запуск: bash ai-setup.sh
|
||||
# ============================================================
|
||||
|
||||
@@ -1684,6 +1684,140 @@ claude --dangerously-skip-permissions --effort "${AI_EFFORT:-xhigh}" --system-pr
|
||||
GLMEOF
|
||||
chmod +x "$BIN_DIR/ai-glm"
|
||||
|
||||
# === ai-eltex ===
|
||||
cat > "$BIN_DIR/ai-eltex" << 'ELTEXEOF'
|
||||
#!/usr/bin/env bash
|
||||
# ai-eltex - запуск Claude Code через корпоративный LLM-прокси Eltex (LiteLLM, team-подписка GLM).
|
||||
# Персональный ключ выдают админы. Дока:
|
||||
# https://intdocs.eltex.loc/pages/viewpage.action?pageId=262329878
|
||||
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/ai-api-helpers.sh" 2>/dev/null || true
|
||||
|
||||
key_file="$HOME/.config/ai-setup/eltex_key"
|
||||
api_key=""
|
||||
reauth=0
|
||||
|
||||
# Принудительный сброс сохранённого ключа через AI_RESET_KEY=1
|
||||
if [ "${AI_RESET_KEY:-0}" == "1" ] && [ -f "$key_file" ]; then
|
||||
rm -f "$key_file"
|
||||
api_key=""
|
||||
fi
|
||||
|
||||
[ -f "$key_file" ] && api_key=$(cat "$key_file")
|
||||
|
||||
eltex_base_url="${ELTEX_BASE_URL:-http://llm.eltex.loc:4000}"
|
||||
|
||||
# _eltex_check_key: проверка ключа через GET /v1/models. Виртуальному ключу LiteLLM
|
||||
# доступны только LLM-роуты, а /v1/models заодно отдаёт модели, разрешённые ключу.
|
||||
_eltex_check_key() {
|
||||
local response
|
||||
# Без "|| echo 000": при сетевой ошибке -w сам печатает 000.
|
||||
response=$(curl -s -w "\n%{http_code}" --max-time 15 "$eltex_base_url/v1/models" \
|
||||
-H "Authorization: Bearer $1" \
|
||||
2>/dev/null)
|
||||
_CLAUDE_TEST_CODE=$(echo "$response" | tail -1)
|
||||
_CLAUDE_TEST_BODY=$(echo "$response" | sed '$d')
|
||||
if [ "$_CLAUDE_TEST_CODE" = "000" ]; then
|
||||
echo ""
|
||||
echo -e "\033[0;31m[СЕТЬ]\033[0m Прокси $eltex_base_url недоступен."
|
||||
echo " Нужна сеть Eltex. Если не резолвится llm.eltex.loc - перезапусти ru-bypass (добавит его в /etc/hosts)"
|
||||
echo " или задай адрес явно: ELTEX_BASE_URL=http://172.16.4.68:4000 ai-eltex"
|
||||
exit 1
|
||||
fi
|
||||
_handle_openai_api_response "Eltex LLM" "$_CLAUDE_TEST_CODE" "$_CLAUDE_TEST_BODY" "Лимит team-подписки исчерпан - обратись к админам"
|
||||
}
|
||||
|
||||
if [ -n "$api_key" ]; then
|
||||
echo -n "Проверка сохранённого Eltex ключа... "
|
||||
_eltex_check_key "$api_key"
|
||||
ret=$_API_RET
|
||||
if [ $ret -eq 401 ]; then
|
||||
rm -f "$key_file"
|
||||
api_key=""
|
||||
reauth=1
|
||||
elif [ $ret -eq 429 ]; then
|
||||
echo -n "Продолжить всё равно? (запросы могут не проходить) [y/N] "
|
||||
read -r _ans; case "${_ans:-N}" in [Yy]*) ;; *) exit 1 ;; esac
|
||||
elif [ $ret -ne 0 ]; then
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$api_key" ] && [ "$reauth" -eq 1 ]; then
|
||||
echo -n "Хотите ввести новый Eltex ключ? [Y/n] "
|
||||
read -r _ans; case "${_ans:-Y}" in [Yy]*) ;; *) exit 1 ;; esac
|
||||
fi
|
||||
|
||||
if [ -z "$api_key" ]; then
|
||||
echo "Ключ выдают админы: https://intdocs.eltex.loc/pages/viewpage.action?pageId=262329878"
|
||||
read -r -p "Введите ваш Eltex LLM ключ (sk-...): " api_key
|
||||
[ -z "$api_key" ] && { echo "Выход."; exit 1; }
|
||||
|
||||
echo -n "Проверяю ключ... "
|
||||
_eltex_check_key "$api_key"
|
||||
ret=$_API_RET
|
||||
if [ $ret -eq 0 ] || [ $ret -eq 429 ]; then
|
||||
mkdir -p "$(dirname "$key_file")"
|
||||
echo "$api_key" > "$key_file"
|
||||
chmod 600 "$key_file"
|
||||
echo "Ключ сохранён."
|
||||
if [ $ret -eq 429 ]; then
|
||||
echo -n "Продолжить всё равно? (запросы могут не проходить) [y/N] "
|
||||
read -r _ans; case "${_ans:-N}" in [Yy]*) ;; *) exit 1 ;; esac
|
||||
fi
|
||||
else
|
||||
echo "Ключ НЕ сохранён."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Модель: ELTEX_MODEL, иначе первая из разрешённых ключу (у разных ключей разные модели,
|
||||
# например zai-glm-5.3 или Eltex-Coder-Senior из доки).
|
||||
model="${ELTEX_MODEL:-}"
|
||||
if [ -z "$model" ]; then
|
||||
model=$(echo "$_CLAUDE_TEST_BODY" | python3 -c '
|
||||
import sys, json
|
||||
ids = [m["id"] for m in json.load(sys.stdin).get("data", [])]
|
||||
print(ids[0] if ids else "")' 2>/dev/null)
|
||||
fi
|
||||
model="${model:-zai-glm-5.3}"
|
||||
echo "Модель: $model"
|
||||
|
||||
_PROMPT_FILE=$(mktemp /tmp/ai-sys-prompt.XXXXXX)
|
||||
trap 'rm -f "$_PROMPT_FILE"' EXIT INT TERM
|
||||
_build_ai_sys_prompt > "$_PROMPT_FILE"
|
||||
export AI_LAUNCHER=eltex
|
||||
export CLAUDE_CONFIG_DIR="$HOME/.config/ai-setup/cfg/eltex"
|
||||
# Пикер: все три слота = модель ключа. availableModels НЕ задаём (он схлопывает пикер);
|
||||
# незаданный слот показал бы чужой Claude.
|
||||
# Прокси сам транслирует запросы в OpenAI-формат и игнорирует effort/thinking (GLM
|
||||
# думает всегда), поэтому CLAUDE_CODE_ALWAYS_ENABLE_EFFORT не нужен, а /effort ни на что
|
||||
# не влияет.
|
||||
# Env из доки админов: API_TIMEOUT_MS (прокси бывает медленным), автокомпакт на 200K.
|
||||
# ENABLE_TOOL_SEARCH: со сторонним ANTHROPIC_BASE_URL Claude Code отключает отложенную
|
||||
# загрузку MCP-тулов; эндпоинт llm2 tool_reference поддерживает (комментарии к доке).
|
||||
_setup_isolated_config eltex opus high ''
|
||||
_apply_effort eltex high
|
||||
ANTHROPIC_BASE_URL="$eltex_base_url" \
|
||||
ANTHROPIC_AUTH_TOKEN="$api_key" \
|
||||
ANTHROPIC_DEFAULT_OPUS_MODEL="$model" \
|
||||
ANTHROPIC_DEFAULT_OPUS_MODEL_NAME="$model" \
|
||||
ANTHROPIC_DEFAULT_OPUS_MODEL_DESCRIPTION="$model - корпоративный прокси Eltex" \
|
||||
ANTHROPIC_DEFAULT_SONNET_MODEL="$model" \
|
||||
ANTHROPIC_DEFAULT_SONNET_MODEL_NAME="$model" \
|
||||
ANTHROPIC_DEFAULT_SONNET_MODEL_DESCRIPTION="$model - корпоративный прокси Eltex" \
|
||||
ANTHROPIC_DEFAULT_HAIKU_MODEL="$model" \
|
||||
ANTHROPIC_DEFAULT_HAIKU_MODEL_NAME="$model" \
|
||||
ANTHROPIC_DEFAULT_HAIKU_MODEL_DESCRIPTION="$model - корпоративный прокси Eltex" \
|
||||
CLAUDE_CODE_SUBAGENT_MODEL="$model" \
|
||||
CLAUDE_CODE_AUTO_COMPACT_WINDOW=200000 \
|
||||
CLAUDE_CODE_DISABLE_1M_CONTEXT=1 \
|
||||
CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1 \
|
||||
API_TIMEOUT_MS=600000 \
|
||||
ENABLE_TOOL_SEARCH=true \
|
||||
claude --dangerously-skip-permissions --system-prompt-file "$_PROMPT_FILE" "$@"
|
||||
ELTEXEOF
|
||||
chmod +x "$BIN_DIR/ai-eltex"
|
||||
|
||||
# === ai-openrouter ===
|
||||
cat > "$BIN_DIR/ai-openrouter" << 'OPENROUTEREOF'
|
||||
#!/usr/bin/env bash
|
||||
@@ -1985,6 +2119,7 @@ source "$BIN_DIR/ai-api-helpers.sh"
|
||||
_setup_isolated_config deepseek opus high ''
|
||||
_setup_isolated_config kimi opus high ''
|
||||
_setup_isolated_config glm opus xhigh ''
|
||||
_setup_isolated_config eltex opus high ''
|
||||
_setup_isolated_config openrouter "openai/gpt-5.5" high ''
|
||||
_setup_isolated_config opencode deepseek-v4-pro high ''
|
||||
|
||||
@@ -1995,7 +2130,7 @@ rm -f "$BIN_DIR/claude_gpt" "$BIN_DIR/claude_deepseek" "$BIN_DIR/claude_kimi" "$
|
||||
if [ "$BIN_DIR" != "$HOME/.local/bin" ]; then
|
||||
warn "BIN_DIR=$BIN_DIR — удаляю старые скрипты из ~/.local/bin/ ..."
|
||||
rm -f "$HOME/.local/bin/ai-gpt" "$HOME/.local/bin/ai-deepseek" "$HOME/.local/bin/ai-kimi" \
|
||||
"$HOME/.local/bin/ai-glm" "$HOME/.local/bin/ai-openrouter" "$HOME/.local/bin/ai-gemini" "$HOME/.local/bin/ai-cursor" "$HOME/.local/bin/ai-claude" \
|
||||
"$HOME/.local/bin/ai-glm" "$HOME/.local/bin/ai-eltex" "$HOME/.local/bin/ai-openrouter" "$HOME/.local/bin/ai-gemini" "$HOME/.local/bin/ai-cursor" "$HOME/.local/bin/ai-claude" \
|
||||
"$HOME/.local/bin/ai-opencode" \
|
||||
"$HOME/.local/bin/ai-api-helpers.sh" "$HOME/.local/bin/claude-gpt-effort-proxy.py"
|
||||
fi
|
||||
@@ -2015,6 +2150,7 @@ echo -e " ${CYAN}ai-claude${NC} - Оригинальный Claude Co
|
||||
echo -e " ${CYAN}ai-deepseek${NC} - DeepSeek (через Claude Code, API ключ сохраняется)"
|
||||
echo -e " ${CYAN}ai-kimi${NC} - Kimi K2.7 Code (через Claude Code, API ключ сохраняется)"
|
||||
echo -e " ${CYAN}ai-glm${NC} - GLM 5.3 (через Claude Code, Zhipu AI API)"
|
||||
echo -e " ${CYAN}ai-eltex${NC} - Корпоративный LLM-прокси Eltex (через Claude Code, ключ от админов)"
|
||||
echo -e " ${CYAN}ai-openrouter${NC} - OpenRouter (через Claude Code: GPT-5.5, Grok, Qwen, GLM 5.2 и др.)"
|
||||
echo -e " ${CYAN}ai-opencode${NC} - OpenCode Go (через Claude Code + routatic-proxy: DeepSeek, Kimi, Qwen, GLM, MiniMax, MiMo)"
|
||||
echo ""
|
||||
|
||||
Reference in New Issue
Block a user