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:
@@ -2,4 +2,4 @@
|
|||||||
|
|
||||||
Данные правила применяются ко всем агентам, работающим конкретно в этом репозитории.
|
Данные правила применяются ко всем агентам, работающим конкретно в этом репозитории.
|
||||||
|
|
||||||
1. **Полная перегенерация standalone-скриптов при запуске сетап-скрипта (Full regeneration of standalone scripts on setup run):** При каждом запуске `ai-setup.sh` все генерируемые скрипты в выбранном `BIN_DIR` (`~/bin`, если он уже есть в `PATH`, иначе `~/.local/bin`: `ai-gpt`, `ai-deepseek`, `ai-kimi`, `ai-glm`, `ai-openrouter`, `ai-gemini`, `ai-api-helpers.sh`, `ai-claude`, `claude-gpt-effort-proxy.py`) должны быть **полностью перезаписаны** актуальными версиями. Запрещено выполнять слияние (merge) старого и нового содержимого или дополнение (append). Скрипт обязан привести все генерируемые файлы к эталонному виду, однозначно определяемому текущей конфигурацией.
|
1. **Полная перегенерация standalone-скриптов при запуске сетап-скрипта (Full regeneration of standalone scripts on setup run):** При каждом запуске `ai-setup.sh` все генерируемые скрипты в выбранном `BIN_DIR` (`~/bin`, если он уже есть в `PATH`, иначе `~/.local/bin`: `ai-gpt`, `ai-deepseek`, `ai-kimi`, `ai-glm`, `ai-eltex`, `ai-openrouter`, `ai-gemini`, `ai-api-helpers.sh`, `ai-claude`, `claude-gpt-effort-proxy.py`) должны быть **полностью перезаписаны** актуальными версиями. Запрещено выполнять слияние (merge) старого и нового содержимого или дополнение (append). Скрипт обязан привести все генерируемые файлы к эталонному виду, однозначно определяемому текущей конфигурацией.
|
||||||
|
|||||||
@@ -140,3 +140,5 @@ ai-deepseek # без флага - использовать ур
|
|||||||
- `max` effort имеет реальный эффект у Anthropic, DeepSeek и GLM; у Kimi это всё тот же thinking on.
|
- `max` effort имеет реальный эффект у Anthropic, DeepSeek и GLM; у Kimi это всё тот же thinking on.
|
||||||
- `low`/`medium` у Kimi фактически не снижают reasoning; у DeepSeek `low` и у GLM `low`/`medium` дают реальный уровень `low` и экономят бюджет.
|
- `low`/`medium` у Kimi фактически не снижают reasoning; у DeepSeek `low` и у GLM `low`/`medium` дают реальный уровень `low` и экономят бюджет.
|
||||||
- У GLM осмысленно выбирать только `low`, `high` (или `xhigh`) и `max`.
|
- У GLM осмысленно выбирать только `low`, `high` (или `xhigh`) и `max`.
|
||||||
|
- `ai-eltex`: корпоративный прокси Eltex (LiteLLM) игнорирует effort и thinking, GLM за ним
|
||||||
|
думает всегда одинаково. `/effort` и `AI_EFFORT` там ни на что не влияют.
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ bash setup.sh
|
|||||||
```
|
```
|
||||||
|
|
||||||
Установит лаунчеры
|
Установит лаунчеры
|
||||||
`ai-claude`, `ai-gpt`, `ai-deepseek`, `ai-kimi`, `ai-glm`, `ai-openrouter`, `ai-opencode`, `ai-gemini`, `ai-cursor`
|
`ai-claude`, `ai-gpt`, `ai-deepseek`, `ai-kimi`, `ai-glm`, `ai-eltex`, `ai-openrouter`, `ai-opencode`, `ai-gemini`, `ai-cursor`
|
||||||
в `~/bin`, если он уже есть в `PATH`, иначе в `~/.local/bin/`, и запишет API-ключи.
|
в `~/bin`, если он уже есть в `PATH`, иначе в `~/.local/bin/`, и запишет API-ключи.
|
||||||
|
|
||||||
После установки, если команды не видны:
|
После установки, если команды не видны:
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ sudo GATEWAY=10.0.0.1 DEV=eth0 bash scripts/ru-bypass.sh
|
|||||||
- `ru-bypass.timer` - ежедневно запускает обновление RIPE-списка и маршрутов
|
- `ru-bypass.timer` - ежедневно запускает обновление RIPE-списка и маршрутов
|
||||||
- NM dispatcher `/etc/NetworkManager/dispatcher.d/99-ru-bypass` - перезапускает скрипт при поднятии amn0
|
- NM dispatcher `/etc/NetworkManager/dispatcher.d/99-ru-bypass` - перезапускает скрипт при поднятии amn0
|
||||||
- `/etc/ru-bypass.conf` - root-конфиг для запусков из systemd/NM dispatcher
|
- `/etc/ru-bypass.conf` - root-конфиг для запусков из systemd/NM dispatcher
|
||||||
- `/etc/hosts` блок для локальных Eltex-доменов
|
- `/etc/hosts` блок для локальных Eltex-доменов (между `# ru-bypass: local hosts` и `# ru-bypass: end`; ручные записи вне блока скрипт не трогает)
|
||||||
|
|
||||||
При каждом запуске:
|
При каждом запуске:
|
||||||
|
|
||||||
@@ -161,6 +161,7 @@ bash tests/test_network.sh # полные тесты
|
|||||||
- `ai-deepseek` - Claude Code через DeepSeek API
|
- `ai-deepseek` - Claude Code через DeepSeek API
|
||||||
- `ai-kimi` - Claude Code через официальный Kimi Code API (`api.kimi.com/coding`)
|
- `ai-kimi` - Claude Code через официальный Kimi Code API (`api.kimi.com/coding`)
|
||||||
- `ai-glm` - Claude Code через Zhipu AI GLM 5.3 API (`api.z.ai/api/anthropic`)
|
- `ai-glm` - Claude Code через Zhipu AI GLM 5.3 API (`api.z.ai/api/anthropic`)
|
||||||
|
- `ai-eltex` - Claude Code через корпоративный LLM-прокси Eltex (`http://llm.eltex.loc:4000`, LiteLLM, team-подписка GLM). Ключ выдают админы ([дока](https://intdocs.eltex.loc/pages/viewpage.action?pageId=262329878)), модель берётся из списка разрешённых ключу; переопределение: `ELTEX_MODEL`, `ELTEX_BASE_URL`
|
||||||
- `ai-openrouter` - Claude Code через OpenRouter (GPT-5.5, Grok, Qwen, GLM 5.2 и др.)
|
- `ai-openrouter` - Claude Code через OpenRouter (GPT-5.5, Grok, Qwen, GLM 5.2 и др.)
|
||||||
- `ai-opencode` - Claude Code через OpenCode Go + routatic-proxy (DeepSeek, Kimi, Qwen, GLM, MiniMax, MiMo)
|
- `ai-opencode` - Claude Code через OpenCode Go + routatic-proxy (DeepSeek, Kimi, Qwen, GLM, MiniMax, MiMo)
|
||||||
- `ai-gemini` - нативный Antigravity CLI `agy`
|
- `ai-gemini` - нативный Antigravity CLI `agy`
|
||||||
@@ -218,6 +219,7 @@ android init
|
|||||||
- `~/.config/ai-setup/deepseek_key` - DeepSeek API key (права 600)
|
- `~/.config/ai-setup/deepseek_key` - DeepSeek API key (права 600)
|
||||||
- `~/.config/ai-setup/kimi_key` - Kimi API key (права 600)
|
- `~/.config/ai-setup/kimi_key` - Kimi API key (права 600)
|
||||||
- `~/.config/ai-setup/glm_key` - Zhipu AI (GLM) API key (права 600)
|
- `~/.config/ai-setup/glm_key` - Zhipu AI (GLM) API key (права 600)
|
||||||
|
- `~/.config/ai-setup/eltex_key` - ключ корпоративного LLM-прокси Eltex от админов (права 600)
|
||||||
- `~/.config/ai-setup/openrouter_key` - OpenRouter API key (права 600)
|
- `~/.config/ai-setup/openrouter_key` - OpenRouter API key (права 600)
|
||||||
- `~/.config/ai-setup/opencode_key` - OpenCode Go API key (права 600)
|
- `~/.config/ai-setup/opencode_key` - OpenCode Go API key (права 600)
|
||||||
- `~/.config/ai-setup/global_rules.md` - глобальные правила агентов
|
- `~/.config/ai-setup/global_rules.md` - глобальные правила агентов
|
||||||
@@ -226,7 +228,7 @@ android init
|
|||||||
## Права запуска агентов
|
## Права запуска агентов
|
||||||
|
|
||||||
- `ai-gpt` использует `--dangerously-bypass-approvals-and-sandbox`
|
- `ai-gpt` использует `--dangerously-bypass-approvals-and-sandbox`
|
||||||
- `ai-claude`, `ai-deepseek`, `ai-kimi`, `ai-glm`, `ai-openrouter`, `ai-opencode`, `ai-gemini` используют `--dangerously-skip-permissions`
|
- `ai-claude`, `ai-deepseek`, `ai-kimi`, `ai-glm`, `ai-eltex`, `ai-openrouter`, `ai-opencode`, `ai-gemini` используют `--dangerously-skip-permissions`
|
||||||
- `ai-cursor` использует `--force` (алиас `--yolo`)
|
- `ai-cursor` использует `--force` (алиас `--yolo`)
|
||||||
|
|
||||||
Удобно для локального coding workflow, но это не sandbox для недоверенного кода.
|
Удобно для локального coding workflow, но это не sandbox для недоверенного кода.
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# Copyright (c) 2026 Виталий Никитенко. MIT License.
|
# Copyright (c) 2026 Виталий Никитенко. MIT License.
|
||||||
# UserPromptSubmit hook: перехватывает /logout, /logout-glm, /logout-deepseek, /logout-kimi.
|
# UserPromptSubmit hook: перехватывает /logout, /logout-glm, /logout-eltex, /logout-deepseek, /logout-kimi.
|
||||||
# Удаляет сохранённый API-ключ провайдера, чтобы при следующем запуске лаунчер
|
# Удаляет сохранённый API-ключ провайдера, чтобы при следующем запуске лаунчер
|
||||||
# запросил новый.
|
# запросил новый.
|
||||||
# /logout-glm | /logout-deepseek | /logout-kimi — явно указанный провайдер.
|
# /logout-glm | /logout-eltex | /logout-deepseek | /logout-kimi — явно указанный провайдер.
|
||||||
# /logout (без суффикса) — провайдер по AI_LAUNCHER (glm/deepseek/kimi).
|
# /logout (без суффикса) — провайдер по AI_LAUNCHER (glm/eltex/deepseek/kimi).
|
||||||
# Для ai-claude и прочих лаунчеров /logout отступает (exit 0) — пусть работает
|
# Для ai-claude и прочих лаунчеров /logout отступает (exit 0) — пусть работает
|
||||||
# нативный oauth-logout. exit 2 после удаления: LLM не нужна, и нативная
|
# нативный oauth-logout. exit 2 после удаления: LLM не нужна, и нативная
|
||||||
# /logout не пытается сделать бессмысленный oauth-logout для api-key провайдеров.
|
# /logout не пытается сделать бессмысленный oauth-logout для api-key провайдеров.
|
||||||
@@ -17,11 +17,12 @@ cmd=$(echo "$normalized" | awk '{print $1}')
|
|||||||
target=""
|
target=""
|
||||||
case "$cmd" in
|
case "$cmd" in
|
||||||
logout-glm) target=glm ;;
|
logout-glm) target=glm ;;
|
||||||
|
logout-eltex) target=eltex ;;
|
||||||
logout-deepseek) target=deepseek ;;
|
logout-deepseek) target=deepseek ;;
|
||||||
logout-kimi) target=kimi ;;
|
logout-kimi) target=kimi ;;
|
||||||
logout)
|
logout)
|
||||||
case "${AI_LAUNCHER:-claude}" in
|
case "${AI_LAUNCHER:-claude}" in
|
||||||
glm|deepseek|kimi) target="$AI_LAUNCHER" ;;
|
glm|eltex|deepseek|kimi) target="$AI_LAUNCHER" ;;
|
||||||
*) exit 0 ;;
|
*) exit 0 ;;
|
||||||
esac
|
esac
|
||||||
;;
|
;;
|
||||||
@@ -35,6 +36,10 @@ case "$target" in
|
|||||||
rm -f "$CFG/glm_key"
|
rm -f "$CFG/glm_key"
|
||||||
echo "✓ GLM ключ удалён. Перезапусти ai-glm, чтобы ввести новый." >&2
|
echo "✓ GLM ключ удалён. Перезапусти ai-glm, чтобы ввести новый." >&2
|
||||||
;;
|
;;
|
||||||
|
eltex)
|
||||||
|
rm -f "$CFG/eltex_key"
|
||||||
|
echo "✓ Eltex ключ удалён. Перезапусти ai-eltex, чтобы ввести новый." >&2
|
||||||
|
;;
|
||||||
deepseek)
|
deepseek)
|
||||||
rm -f "$CFG/deepseek_key"
|
rm -f "$CFG/deepseek_key"
|
||||||
echo "✓ DeepSeek ключ удалён. Перезапусти ai-deepseek, чтобы ввести новый." >&2
|
echo "✓ DeepSeek ключ удалён. Перезапусти ai-deepseek, чтобы ввести новый." >&2
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ before.rules: 10/8, 172.16/12,
|
|||||||
5. Добавляет маршруты для RFC1918 диапазонов (`10/8`, `172.16/12`, `192.168/16`) - нужно для `*.loc`
|
5. Добавляет маршруты для RFC1918 диапазонов (`10/8`, `172.16/12`, `192.168/16`) - нужно для `*.loc`
|
||||||
6. Добавляет встроенные исключения kill switch (`mattermost.eltex-co.ru`, `elph.eltex-co.ru`, `10.80.0.15`)
|
6. Добавляет встроенные исключения kill switch (`mattermost.eltex-co.ru`, `elph.eltex-co.ru`, `10.80.0.15`)
|
||||||
7. Добавляет пользовательские исключения из `AMNEZIA_SERVER` и `KILL_SWITCH_EXCEPTIONS`
|
7. Добавляет пользовательские исключения из `AMNEZIA_SERVER` и `KILL_SWITCH_EXCEPTIONS`
|
||||||
8. Обновляет блок локальных Eltex-хостов в `/etc/hosts`
|
8. Обновляет блок локальных Eltex-хостов в `/etc/hosts` (только между маркерами `# ru-bypass: local hosts` / `# ru-bypass: end`, ручные записи сохраняются)
|
||||||
9. Если задан `LOCAL_DNS`, настраивает `resolvectl` для `~loc` на интерфейсе `DEV`
|
9. Если задан `LOCAL_DNS`, настраивает `resolvectl` для `~loc` на интерфейсе `DEV`
|
||||||
10. Обновляет `/etc/ufw/before.rules`, прямые iptables-правила и отключает IPv6 при активном kill switch
|
10. Обновляет `/etc/ufw/before.rules`, прямые iptables-правила и отключает IPv6 при активном kill switch
|
||||||
11. При первом запуске: устанавливает systemd service/timer и NetworkManager dispatcher
|
11. При первом запуске: устанавливает systemd service/timer и NetworkManager dispatcher
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# Copyright (c) 2026 Виталий Никитенко. MIT License.
|
# 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
|
# Запуск: bash ai-setup.sh
|
||||||
# ============================================================
|
# ============================================================
|
||||||
|
|
||||||
@@ -1684,6 +1684,140 @@ claude --dangerously-skip-permissions --effort "${AI_EFFORT:-xhigh}" --system-pr
|
|||||||
GLMEOF
|
GLMEOF
|
||||||
chmod +x "$BIN_DIR/ai-glm"
|
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 ===
|
# === ai-openrouter ===
|
||||||
cat > "$BIN_DIR/ai-openrouter" << 'OPENROUTEREOF'
|
cat > "$BIN_DIR/ai-openrouter" << 'OPENROUTEREOF'
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
@@ -1985,6 +2119,7 @@ source "$BIN_DIR/ai-api-helpers.sh"
|
|||||||
_setup_isolated_config deepseek opus high ''
|
_setup_isolated_config deepseek opus high ''
|
||||||
_setup_isolated_config kimi opus high ''
|
_setup_isolated_config kimi opus high ''
|
||||||
_setup_isolated_config glm opus xhigh ''
|
_setup_isolated_config glm opus xhigh ''
|
||||||
|
_setup_isolated_config eltex opus high ''
|
||||||
_setup_isolated_config openrouter "openai/gpt-5.5" high ''
|
_setup_isolated_config openrouter "openai/gpt-5.5" high ''
|
||||||
_setup_isolated_config opencode deepseek-v4-pro 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
|
if [ "$BIN_DIR" != "$HOME/.local/bin" ]; then
|
||||||
warn "BIN_DIR=$BIN_DIR — удаляю старые скрипты из ~/.local/bin/ ..."
|
warn "BIN_DIR=$BIN_DIR — удаляю старые скрипты из ~/.local/bin/ ..."
|
||||||
rm -f "$HOME/.local/bin/ai-gpt" "$HOME/.local/bin/ai-deepseek" "$HOME/.local/bin/ai-kimi" \
|
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-opencode" \
|
||||||
"$HOME/.local/bin/ai-api-helpers.sh" "$HOME/.local/bin/claude-gpt-effort-proxy.py"
|
"$HOME/.local/bin/ai-api-helpers.sh" "$HOME/.local/bin/claude-gpt-effort-proxy.py"
|
||||||
fi
|
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-deepseek${NC} - DeepSeek (через Claude Code, API ключ сохраняется)"
|
||||||
echo -e " ${CYAN}ai-kimi${NC} - Kimi K2.7 Code (через 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-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-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 -e " ${CYAN}ai-opencode${NC} - OpenCode Go (через Claude Code + routatic-proxy: DeepSeek, Kimi, Qwen, GLM, MiniMax, MiMo)"
|
||||||
echo ""
|
echo ""
|
||||||
|
|||||||
@@ -162,10 +162,12 @@ fi
|
|||||||
# Без этого DNS через VPN может вернуть внешний IP вместо внутреннего,
|
# Без этого DNS через VPN может вернуть внешний IP вместо внутреннего,
|
||||||
# и трафик пойдёт через VPN вместо прямого соединения.
|
# и трафик пойдёт через VPN вместо прямого соединения.
|
||||||
HOSTS_MARKER="# ru-bypass: local hosts"
|
HOSTS_MARKER="# ru-bypass: local hosts"
|
||||||
|
HOSTS_END_MARKER="# ru-bypass: end"
|
||||||
|
|
||||||
# Удаляем старый блок целиком (от маркера до конца файла)
|
# Удаляем только свой блок (от маркера до конечного маркера).
|
||||||
# и заодно чистим дубликаты от старых версий скрипта (без маркера)
|
# Записи, добавленные вручную вне блока, не трогаем.
|
||||||
sed -i "/$HOSTS_MARKER/,\$ d; /eltex\.loc/d; /eltex-co\.ru/d" /etc/hosts
|
# Блок старых версий без конечного маркера удаляется до конца файла.
|
||||||
|
sed -i "/^$HOSTS_MARKER\$/,/^$HOSTS_END_MARKER\$/d" /etc/hosts
|
||||||
|
|
||||||
# Добавляем актуальные
|
# Добавляем актуальные
|
||||||
cat >> /etc/hosts <<_HOSTS
|
cat >> /etc/hosts <<_HOSTS
|
||||||
@@ -180,8 +182,10 @@ $HOSTS_MARKER
|
|||||||
172.16.5.63 proxy.eltex.loc
|
172.16.5.63 proxy.eltex.loc
|
||||||
10.80.0.16 ssw.eltex.loc
|
10.80.0.16 ssw.eltex.loc
|
||||||
172.16.5.78 nexus.eltex.loc
|
172.16.5.78 nexus.eltex.loc
|
||||||
|
172.16.4.68 llm.eltex.loc llm2.eltex.loc
|
||||||
172.16.1.149 cpe-worker.eltex.loc
|
172.16.1.149 cpe-worker.eltex.loc
|
||||||
172.16.5.22 mattermost.eltex-co.ru elph.eltex-co.ru ecss-elph-proxy.eltex-co.ru study-git.eltex-co.ru study-red.eltex-co.ru
|
172.16.5.22 mattermost.eltex-co.ru elph.eltex-co.ru ecss-elph-proxy.eltex-co.ru study-git.eltex-co.ru study-red.eltex-co.ru
|
||||||
|
$HOSTS_END_MARKER
|
||||||
_HOSTS
|
_HOSTS
|
||||||
|
|
||||||
echo "Локальные хосты: *.eltex.loc, mattermost, elph → /etc/hosts"
|
echo "Локальные хосты: *.eltex.loc, mattermost, elph → /etc/hosts"
|
||||||
|
|||||||
4
setup.sh
4
setup.sh
@@ -230,7 +230,7 @@ case "$choice" in
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
echo -e "${BLD}AI инструменты:${CLR}"
|
echo -e "${BLD}AI инструменты:${CLR}"
|
||||||
for cmd in ai-claude ai-gpt ai-deepseek ai-kimi ai-glm ai-openrouter ai-opencode ai-gemini android; do
|
for cmd in ai-claude ai-gpt ai-deepseek ai-kimi ai-glm ai-eltex ai-openrouter ai-opencode ai-gemini android; do
|
||||||
if command -v "$cmd" &>/dev/null; then
|
if command -v "$cmd" &>/dev/null; then
|
||||||
echo -e " ${GRN}✓${CLR} $cmd"
|
echo -e " ${GRN}✓${CLR} $cmd"
|
||||||
else
|
else
|
||||||
@@ -241,7 +241,7 @@ case "$choice" in
|
|||||||
echo ""
|
echo ""
|
||||||
echo -e "${BLD}API ключи:${CLR}"
|
echo -e "${BLD}API ключи:${CLR}"
|
||||||
cfg="$HOME/.config/ai-setup"
|
cfg="$HOME/.config/ai-setup"
|
||||||
for f in deepseek_key kimi_key glm_key openrouter_key opencode_key; do
|
for f in deepseek_key kimi_key glm_key eltex_key openrouter_key opencode_key; do
|
||||||
name="${f/_key/}"
|
name="${f/_key/}"
|
||||||
if [ -s "$cfg/$f" ]; then
|
if [ -s "$cfg/$f" ]; then
|
||||||
echo -e " ${GRN}✓${CLR} $name"
|
echo -e " ${GRN}✓${CLR} $name"
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ fail() { echo "[FAIL] $1"; FAIL=$((FAIL+1)); }
|
|||||||
GPT_SECTION=$(awk '/^cat > "\$BIN_DIR\/ai-gpt"/,/^GPTEOF/' "$SCRIPT")
|
GPT_SECTION=$(awk '/^cat > "\$BIN_DIR\/ai-gpt"/,/^GPTEOF/' "$SCRIPT")
|
||||||
KIMI_SECTION=$(awk '/^cat > "\$BIN_DIR\/ai-kimi"/,/^KIMIEOF/' "$SCRIPT")
|
KIMI_SECTION=$(awk '/^cat > "\$BIN_DIR\/ai-kimi"/,/^KIMIEOF/' "$SCRIPT")
|
||||||
GLM_SECTION=$(awk '/^cat > "\$BIN_DIR\/ai-glm"/,/^GLMEOF/' "$SCRIPT")
|
GLM_SECTION=$(awk '/^cat > "\$BIN_DIR\/ai-glm"/,/^GLMEOF/' "$SCRIPT")
|
||||||
|
ELTEX_SECTION=$(awk '/^cat > "\$BIN_DIR\/ai-eltex"/,/^ELTEXEOF/' "$SCRIPT")
|
||||||
|
LOGOUT_HOOK="$(cd "$(dirname "$0")/.." && pwd)/home-configs/claude/hooks/logout-account-hook.sh"
|
||||||
GEMINI_SECTION=$(awk '/^cat > "\$BIN_DIR\/ai-gemini"/,/^GEMINIEOF/' "$SCRIPT")
|
GEMINI_SECTION=$(awk '/^cat > "\$BIN_DIR\/ai-gemini"/,/^GEMINIEOF/' "$SCRIPT")
|
||||||
OPENCODE_SECTION=$(awk '/^cat > "\$BIN_DIR\/ai-opencode"/,/^OPENCODEEOF/' "$SCRIPT")
|
OPENCODE_SECTION=$(awk '/^cat > "\$BIN_DIR\/ai-opencode"/,/^OPENCODEEOF/' "$SCRIPT")
|
||||||
CURSOR_SECTION=$(awk '/^cat > "\$BIN_DIR\/ai-cursor"/,/^CURSOREOF/' "$SCRIPT")
|
CURSOR_SECTION=$(awk '/^cat > "\$BIN_DIR\/ai-cursor"/,/^CURSOREOF/' "$SCRIPT")
|
||||||
@@ -104,6 +106,46 @@ test_glm_official_api() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ── ai-eltex: Claude Code через корпоративный прокси Eltex ─────────────────
|
||||||
|
test_eltex_claude_launcher() {
|
||||||
|
if echo "$ELTEX_SECTION" | grep -q 'claude --dangerously-skip-permissions' \
|
||||||
|
&& echo "$ELTEX_SECTION" | grep -q 'ELTEX_BASE_URL:-http://llm.eltex.loc:4000' \
|
||||||
|
&& echo "$ELTEX_SECTION" | grep -q 'ANTHROPIC_BASE_URL="$eltex_base_url"' \
|
||||||
|
&& echo "$ELTEX_SECTION" | grep -q 'CLAUDE_CONFIG_DIR="$HOME/.config/ai-setup/cfg/eltex"' \
|
||||||
|
&& echo "$ELTEX_SECTION" | grep -q 'key_file="$HOME/.config/ai-setup/eltex_key"'; then
|
||||||
|
ok "ai-eltex: launches claude via llm.eltex.loc with its own key and config dir"
|
||||||
|
else
|
||||||
|
fail "ai-eltex: must launch claude via llm.eltex.loc with eltex_key and cfg/eltex"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# ── ai-eltex: модель берётся из /v1/models ключа ──────────────────────────
|
||||||
|
test_eltex_model_from_key() {
|
||||||
|
if echo "$ELTEX_SECTION" | grep -q '/v1/models' \
|
||||||
|
&& echo "$ELTEX_SECTION" | grep -q 'model="${ELTEX_MODEL:-}"' \
|
||||||
|
&& echo "$ELTEX_SECTION" | grep -q 'ANTHROPIC_DEFAULT_OPUS_MODEL="$model"' \
|
||||||
|
&& echo "$ELTEX_SECTION" | grep -q 'ANTHROPIC_DEFAULT_HAIKU_MODEL="$model"'; then
|
||||||
|
ok "ai-eltex: model resolved from the key's /v1/models (ELTEX_MODEL overrides)"
|
||||||
|
else
|
||||||
|
fail "ai-eltex: model must come from /v1/models or ELTEX_MODEL"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# ── logout hook: /logout-eltex удаляет eltex_key ──────────────────────────
|
||||||
|
test_logout_eltex() {
|
||||||
|
local tmp_home rc=0
|
||||||
|
tmp_home=$(mktemp -d)
|
||||||
|
mkdir -p "$tmp_home/.config/ai-setup"
|
||||||
|
echo "sk-test" > "$tmp_home/.config/ai-setup/eltex_key"
|
||||||
|
echo '{"prompt":"/logout"}' | HOME="$tmp_home" AI_LAUNCHER=eltex bash "$LOGOUT_HOOK" 2>/dev/null || rc=$?
|
||||||
|
if [ "$rc" -eq 2 ] && [ ! -f "$tmp_home/.config/ai-setup/eltex_key" ]; then
|
||||||
|
ok "logout hook: /logout in ai-eltex removes eltex_key"
|
||||||
|
else
|
||||||
|
fail "logout hook: /logout in ai-eltex must remove eltex_key (rc=$rc)"
|
||||||
|
fi
|
||||||
|
rm -rf "$tmp_home"
|
||||||
|
}
|
||||||
|
|
||||||
# ── ai-glm: default effort is xhigh (still overridable via AI_EFFORT) ─────
|
# ── ai-glm: default effort is xhigh (still overridable via AI_EFFORT) ─────
|
||||||
test_glm_default_effort() {
|
test_glm_default_effort() {
|
||||||
if echo "$GLM_SECTION" | grep -q -- '--effort "${AI_EFFORT:-xhigh}"' \
|
if echo "$GLM_SECTION" | grep -q -- '--effort "${AI_EFFORT:-xhigh}"' \
|
||||||
@@ -312,6 +354,9 @@ test_kimi_no_artemox
|
|||||||
test_glm_claude_launcher
|
test_glm_claude_launcher
|
||||||
test_glm_official_api
|
test_glm_official_api
|
||||||
test_glm_default_effort
|
test_glm_default_effort
|
||||||
|
test_eltex_claude_launcher
|
||||||
|
test_eltex_model_from_key
|
||||||
|
test_logout_eltex
|
||||||
test_gemini_native_launcher
|
test_gemini_native_launcher
|
||||||
test_cursor_native_launcher
|
test_cursor_native_launcher
|
||||||
test_global_rules_source_installed
|
test_global_rules_source_installed
|
||||||
|
|||||||
Reference in New Issue
Block a user