Compare commits
2 Commits
709e144a60
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d8be32dd64 | ||
|
|
c74a435d89 |
@@ -188,6 +188,6 @@ 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` (путь прокси `/anthropic`, 20.10): запрос идёт на Anthropic-эндпоинт Z.ai как есть,
|
- `ai-eltex` (21.10): effort у `anth-glm-5.3` (Anthropic-эндпоинт Z.ai через прокси) работает: `low` - без
|
||||||
effort у `glm-5.3` работает: `low` - без размышлений, дальше `medium` < `high` < `max`. Как и `ai-glm`, стартует на `max`
|
размышлений, `medium`/`high`/`max` - с размышлениями. Как и `ai-glm`, стартует на `max`
|
||||||
через CLI `--effort`, `AI_EFFORT=high ai-eltex` работает. У `ai-eltex-qwen` прокси effort игнорирует, `/effort` и `AI_EFFORT` там ни на что не влияют.
|
через CLI `--effort`, `AI_EFFORT=high ai-eltex` работает. У `ai-eltex-qwen` прокси effort игнорирует, `/effort` и `AI_EFFORT` там ни на что не влияют.
|
||||||
|
|||||||
@@ -161,7 +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)), Claude Code ходит в сырой путь прокси `/anthropic`, который пересылает запросы на Anthropic-эндпоинт Z.ai как есть; модель `glm-5.3` во всех слотах `/model` (картинки через серверный `analyze_image`, как в `ai-glm`, effort, окно 1M); если ключу недоступна `glm-5.3`, лаунчер выходит с понятной ошибкой; переопределение: `ELTEX_MODEL`, `ELTEX_BASE_URL`
|
- `ai-eltex` - Claude Code через корпоративный LLM-прокси Eltex (`http://llm.eltex.loc:4000`, LiteLLM, team-подписка GLM). Ключ выдают админы ([дока](https://intdocs.eltex.loc/pages/viewpage.action?pageId=262329878)), модель `anth-glm-5.3` (GLM 5.3 на Anthropic-эндпоинте Z.ai) во всех слотах `/model`: картинки через серверный `analyze_image`, как в `ai-glm`, effort, кеш, окно 1M; если ключу недоступна `anth-glm-5.3`, лаунчер выходит с понятной ошибкой; переопределение: `ELTEX_MODEL`, `ELTEX_BASE_URL`
|
||||||
- `ai-eltex-qwen` - то же через корпоративный LLM-прокси Eltex, но на моделях Qwen со своим ключом от админов: по умолчанию `Eltex-Coder-Senior` (Qwen3.8-27B), если она есть у ключа, иначе `Eltex-Qwen3_8-Flash-Next`; ключ можно задать в `AI_ELTEX_LLM_API_KEY`, как в онбординге Eltex AI; переопределение: `ELTEX_QWEN_MODEL`, `ELTEX_BASE_URL`
|
- `ai-eltex-qwen` - то же через корпоративный LLM-прокси Eltex, но на моделях Qwen со своим ключом от админов: по умолчанию `Eltex-Coder-Senior` (Qwen3.8-27B), если она есть у ключа, иначе `Eltex-Qwen3_8-Flash-Next`; ключ можно задать в `AI_ELTEX_LLM_API_KEY`, как в онбординге Eltex AI; переопределение: `ELTEX_QWEN_MODEL`, `ELTEX_BASE_URL`
|
||||||
- `ai-mimo` - Claude Code через Xiaomi MiMo V2.6 (Anthropic-совместимый API, Token Plan или pay-as-you-go): всегда самая умная модель `mimo-v2.6-pro` (во всех слотах и сабагентах, `--model opus` на каждом запуске), effort `max`, вывод до 128000 токенов, окно 1M. Эндпоинт региона подписки (`token-plan-sgp`/`-ams`, для `sk-` ключа `api.xiaomimimo.com`) находится перебором при вводе ключа; переопределение: `MIMO_BASE_URL` (нужно для `token-plan-cn`: он в перебор не входит, с наших машин не отвечает)
|
- `ai-mimo` - Claude Code через Xiaomi MiMo V2.6 (Anthropic-совместимый API, Token Plan или pay-as-you-go): всегда самая умная модель `mimo-v2.6-pro` (во всех слотах и сабагентах, `--model opus` на каждом запуске), effort `max`, вывод до 128000 токенов, окно 1M. Эндпоинт региона подписки (`token-plan-sgp`/`-ams`, для `sk-` ключа `api.xiaomimimo.com`) находится перебором при вводе ключа; переопределение: `MIMO_BASE_URL` (нужно для `token-plan-cn`: он в перебор не входит, с наших машин не отвечает)
|
||||||
- `ai-qwen` - Claude Code через Alibaba Cloud Model Studio (Token Plan, Anthropic-совместимый API `token-plan.ap-southeast-1.maas.aliyuncs.com/apps/anthropic`): общий ключ вшит в скрипт, запускается сразу без ввода ключа. `qwen3.8-max` в opus/sonnet и сабагентах (`--model opus` на каждом запуске), `qwen3.8-flash` в haiku, effort `max`, окно 1M, картинки видят обе модели
|
- `ai-qwen` - Claude Code через Alibaba Cloud Model Studio (Token Plan, Anthropic-совместимый API `token-plan.ap-southeast-1.maas.aliyuncs.com/apps/anthropic`): общий ключ вшит в скрипт, запускается сразу без ввода ключа. `qwen3.8-max` в opus/sonnet и сабагентах (`--model opus` на каждом запуске), `qwen3.8-flash` в haiku, effort `max`, окно 1M, картинки видят обе модели
|
||||||
@@ -179,7 +179,7 @@ bash tests/test_network.sh # полные тесты
|
|||||||
|
|
||||||
## Android CLI
|
## Android CLI
|
||||||
|
|
||||||
`scripts/ai-setup.sh` также устанавливает [Google Android CLI](https://d.android.com/tools/agents) (preview) - официальный терминальный инструмент для Android-разработки, заточенный под AI-агентов.
|
[Google Android CLI](https://d.android.com/tools/agents) (preview) - официальный терминальный инструмент для Android-разработки, заточенный под AI-агентов. По умолчанию **не устанавливается**: `scripts/ai-setup.sh` (пункты меню 1 и 7) его не трогает. Ставится только по выбору - `bash setup.sh` → пункт `8) Android CLI` (или напрямую `bash scripts/android-cli-setup.sh`).
|
||||||
|
|
||||||
Что устанавливается:
|
Что устанавливается:
|
||||||
- `android` - бинарь CLI в `~/.local/bin/` (или `~/bin` через symlink)
|
- `android` - бинарь CLI в `~/.local/bin/` (или `~/bin` через symlink)
|
||||||
@@ -206,7 +206,7 @@ android update # обновить сам Android CLI
|
|||||||
Интеграция с Claude Code:
|
Интеграция с Claude Code:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# После установки ai-setup.sh выполняется автоматически:
|
# После установки android-cli-setup.sh выполняется автоматически:
|
||||||
android init
|
android init
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -267,56 +267,6 @@ else
|
|||||||
success "agy уже установлен: $(agy --version 2>/dev/null | head -1)"
|
success "agy уже установлен: $(agy --version 2>/dev/null | head -1)"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# ── 4d. Google Android CLI ───────────────────────────────────
|
|
||||||
info "Проверяю Android CLI..."
|
|
||||||
ANDROID_BIN="$HOME/.local/bin/android"
|
|
||||||
[ ! -f "$ANDROID_BIN" ] && ANDROID_BIN="$(command -v android 2>/dev/null || true)"
|
|
||||||
|
|
||||||
if [ -z "$ANDROID_BIN" ] || [ ! -f "$ANDROID_BIN" ]; then
|
|
||||||
info "Устанавливаю Android CLI..."
|
|
||||||
_uname_s=$(uname -s)
|
|
||||||
_uname_m=$(uname -m)
|
|
||||||
ANDROID_PLATFORM=""
|
|
||||||
case "${_uname_s}-${_uname_m}" in
|
|
||||||
Linux-x86_64) ANDROID_PLATFORM="linux_x86_64" ;;
|
|
||||||
Linux-aarch64) ANDROID_PLATFORM="linux_arm64" ;;
|
|
||||||
Linux-arm64) ANDROID_PLATFORM="linux_arm64" ;;
|
|
||||||
Darwin-x86_64) ANDROID_PLATFORM="darwin_x86_64" ;;
|
|
||||||
Darwin-arm64) ANDROID_PLATFORM="darwin_arm64" ;;
|
|
||||||
Darwin-aarch64) ANDROID_PLATFORM="darwin_arm64" ;;
|
|
||||||
MINGW*|MSYS*|CYGWIN*-x86_64) ANDROID_PLATFORM="windows_x86_64" ;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
if [ -n "$ANDROID_PLATFORM" ]; then
|
|
||||||
ANDROID_INSTALL_URL="https://dl.google.com/android/cli/latest/${ANDROID_PLATFORM}/install.sh"
|
|
||||||
if curl -fsSL "$ANDROID_INSTALL_URL" | bash; then
|
|
||||||
success "Android CLI установлен"
|
|
||||||
else
|
|
||||||
warn "Не удалось установить Android CLI через официальный скрипт"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
warn "Неизвестная платформа ${_uname_s} ${_uname_m}. Пропускаю Android CLI."
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
success "Android CLI уже установлен: $($ANDROID_BIN --version 2>/dev/null | head -1)"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Официальный install.sh ставит бинарь в ~/.local/bin/android.
|
|
||||||
# Если пользователь использует ~/bin вместо ~/.local/bin - symlink.
|
|
||||||
if [ "$BIN_DIR" != "$HOME/.local/bin" ] && [ -f "$HOME/.local/bin/android" ] && [ ! -f "$BIN_DIR/android" ]; then
|
|
||||||
ln -sf "$HOME/.local/bin/android" "$BIN_DIR/android"
|
|
||||||
success "Android CLI symlink -> $BIN_DIR/android"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Разворачиваем Android CLI skills для агентов (Claude Code и др.)
|
|
||||||
if command -v android &>/dev/null; then
|
|
||||||
info "Запускаю android init для деплоя skills..."
|
|
||||||
mkdir -p "$HOME/.claude/skills"
|
|
||||||
android init || warn "android init завершился с ошибкой"
|
|
||||||
else
|
|
||||||
info "Android CLI не найден в PATH, пропускаю android init"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ── 5. routatic-proxy (OpenCode Go → Claude Code) ──────────
|
# ── 5. routatic-proxy (OpenCode Go → Claude Code) ──────────
|
||||||
info "Проверяю routatic-proxy..."
|
info "Проверяю routatic-proxy..."
|
||||||
ROUTATIC_BIN="$HOME/.local/bin/routatic-proxy"
|
ROUTATIC_BIN="$HOME/.local/bin/routatic-proxy"
|
||||||
@@ -1731,11 +1681,11 @@ _eltex_check_key() {
|
|||||||
_handle_openai_api_response "Eltex LLM" "$_CLAUDE_TEST_CODE" "$_CLAUDE_TEST_BODY" "Лимит team-подписки исчерпан - обратись к админам"
|
_handle_openai_api_response "Eltex LLM" "$_CLAUDE_TEST_CODE" "$_CLAUDE_TEST_BODY" "Лимит team-подписки исчерпан - обратись к админам"
|
||||||
}
|
}
|
||||||
|
|
||||||
# _eltex_pick_models: модель glm-5.3 из _CLAUDE_TEST_BODY (последний ответ /v1/models).
|
# _eltex_pick_models: модель anth-glm-5.3 из _CLAUDE_TEST_BODY (последний ответ /v1/models).
|
||||||
# Если имя с суффиксом (glm-5.3-2), берём точное имя, иначе первое с тем же префиксом, кроме
|
# Если имя с суффиксом (anth-glm-5.3-2), берём точное имя, иначе первое с тем же префиксом;
|
||||||
# flash; имена групп доступа (ZAI-Test-Group) так не попадут. Список не распарсился
|
# имена групп доступа (ZAI-Test-Group) так не попадут. Список не распарсился
|
||||||
# (429/сетевая ошибка/5xx) - стандартное имя наугад. Распарсился, но glm-5.3 нет - ошибка
|
# (429/сетевая ошибка/5xx) - стандартное имя наугад. Распарсился, но anth-glm-5.3 нет -
|
||||||
# в stderr, model пустой, возврат 1: дефолтный запуск невозможен.
|
# ошибка в stderr, model пустой, возврат 1: дефолтный запуск невозможен.
|
||||||
_eltex_pick_models() {
|
_eltex_pick_models() {
|
||||||
local picked avail
|
local picked avail
|
||||||
if ! picked=$(echo "$_CLAUDE_TEST_BODY" | python3 -c '
|
if ! picked=$(echo "$_CLAUDE_TEST_BODY" | python3 -c '
|
||||||
@@ -1745,15 +1695,15 @@ def pick(exact, prefix, skip=None):
|
|||||||
if exact in ids:
|
if exact in ids:
|
||||||
return exact
|
return exact
|
||||||
return next((i for i in ids if i.startswith(prefix) and not (skip and skip in i)), "-")
|
return next((i for i in ids if i.startswith(prefix) and not (skip and skip in i)), "-")
|
||||||
print(pick("glm-5.3", "glm-5.3-", "flash"), " ".join(ids) or "(пусто)")' 2>/dev/null); then
|
print(pick("anth-glm-5.3", "anth-glm-5.3-"), " ".join(ids) or "(пусто)")' 2>/dev/null); then
|
||||||
model="glm-5.3"
|
model="anth-glm-5.3"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
read -r model avail <<< "$picked"
|
read -r model avail <<< "$picked"
|
||||||
if [ "$model" = "-" ]; then
|
if [ "$model" = "-" ]; then
|
||||||
model=""
|
model=""
|
||||||
echo -e "\033[0;31m[МОДЕЛЬ]\033[0m Ключу недоступна модель glm-5.3. Прокси отдаёт: $avail" >&2
|
echo -e "\033[0;31m[МОДЕЛЬ]\033[0m Ключу недоступна модель anth-glm-5.3. Прокси отдаёт: $avail" >&2
|
||||||
echo " Напиши админам про доступ к glm-5.3 или задай модель явно: ELTEX_MODEL=<имя> ai-eltex" >&2
|
echo " Напиши админам про доступ к anth-glm-5.3 или задай модель явно: ELTEX_MODEL=<имя> ai-eltex" >&2
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
return 0
|
return 0
|
||||||
@@ -1773,7 +1723,7 @@ if [ -n "$api_key" ]; then
|
|||||||
elif [ $ret -ne 0 ]; then
|
elif [ $ret -ne 0 ]; then
|
||||||
exit 1
|
exit 1
|
||||||
elif [ -z "${ELTEX_MODEL:-}" ] && ! _eltex_pick_models; then
|
elif [ -z "${ELTEX_MODEL:-}" ] && ! _eltex_pick_models; then
|
||||||
# Ключ валиден, но glm-5.3 недоступна (не та группа доступа) - авто-логаут,
|
# Ключ валиден, но anth-glm-5.3 недоступна (не та группа доступа) - авто-логаут,
|
||||||
# как при 401: такой ключ не годится для дефолтного запуска, сразу просим новый.
|
# как при 401: такой ключ не годится для дефолтного запуска, сразу просим новый.
|
||||||
echo " Сохранённый ключ удалён (авто-логаут)."
|
echo " Сохранённый ключ удалён (авто-логаут)."
|
||||||
rm -f "$key_file"
|
rm -f "$key_file"
|
||||||
@@ -1814,21 +1764,22 @@ if [ -z "$api_key" ]; then
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Модель: ELTEX_MODEL, иначе glm-5.3. Claude Code ходит в сырой путь прокси /anthropic: он
|
# Модель: ELTEX_MODEL, иначе anth-glm-5.3 - glm-5.3 на Anthropic-эндпоинте Z.ai, Claude Code
|
||||||
# байт-в-байт пересылает запрос на Anthropic-эндпоинт Z.ai (api.z.ai/api/anthropic), как у
|
# ходит в обычный /v1/messages прокси. Проверено 21.10 на всех 6 ключах пилота: картинки
|
||||||
# ai-glm, поэтому картинки работают через серверный analyze_image (20.10: Read png ->
|
# через серверный analyze_image (Read png -> server_tool_use analyze_image -> верный ответ,
|
||||||
# server_tool_use analyze_image -> верный ответ, так же, как напрямую). Обычный /v1/messages
|
# как в ai-glm), effort, кеш (~95% входа со второго вызова), окно >200K. zai-glm-5.3
|
||||||
# прокси для этого не годится: LiteLLM в нём режет картинки. Первую модель из
|
# (OpenAI-эндпоинт, без картинок) и flash не используем. Сырой путь /anthropic на этом
|
||||||
|
# прокси не настроен (21.10: 401 "No Anthropic credential"). Первую модель из
|
||||||
# /v1/models НЕ берём: там бывают не те модели и имена групп доступа (ZAI-Test-Group),
|
# /v1/models НЕ берём: там бывают не те модели и имена групп доступа (ZAI-Test-Group),
|
||||||
# которые не запустить. Если у ключа нет glm-5.3 - авто-логаут выше (свежевведённый такой
|
# которые не запустить. Если у ключа нет anth-glm-5.3 - авто-логаут выше (свежевведённый
|
||||||
# ключ не сохраняется), вместо 400/403 внутри Claude Code. Модель не выбиралась
|
# такой ключ не сохраняется), вместо 400/403 внутри Claude Code. Модель не выбиралась
|
||||||
# (429/сетевая ошибка или задан ELTEX_MODEL) - выбираем здесь.
|
# (429/сетевая ошибка или задан ELTEX_MODEL) - выбираем здесь.
|
||||||
[ -n "${model:-}" ] || _eltex_pick_models 2>/dev/null || true
|
[ -n "${model:-}" ] || _eltex_pick_models 2>/dev/null || true
|
||||||
model="${ELTEX_MODEL:-${model:-glm-5.3}}"
|
model="${ELTEX_MODEL:-${model:-anth-glm-5.3}}"
|
||||||
# Окно 1M через суффикс [1m], а не глобальным CLAUDE_CODE_MAX_CONTEXT_TOKENS (у glm-5.3 на
|
# Окно 1M через суффикс [1m], а не глобальным CLAUDE_CODE_MAX_CONTEXT_TOKENS (через прокси
|
||||||
# Anthropic-эндпоинте Z.ai 07.10 прошёл запрос на 598K); суффикс Claude Code в API не шлёт.
|
# прошли запросы на 598K 07.10 и 309K 21.10); суффикс Claude Code в API не шлёт.
|
||||||
opus_model="$model"
|
opus_model="$model"
|
||||||
case "$model" in glm-5.3*) opus_model="${model}[1m]" ;; esac
|
case "$model" in anth-glm-5.3*) opus_model="${model}[1m]" ;; esac
|
||||||
echo "Модель: $model"
|
echo "Модель: $model"
|
||||||
|
|
||||||
_PROMPT_FILE=$(mktemp /tmp/ai-sys-prompt.XXXXXX)
|
_PROMPT_FILE=$(mktemp /tmp/ai-sys-prompt.XXXXXX)
|
||||||
@@ -1836,13 +1787,13 @@ trap 'rm -f "$_PROMPT_FILE"' EXIT INT TERM
|
|||||||
_build_ai_sys_prompt > "$_PROMPT_FILE"
|
_build_ai_sys_prompt > "$_PROMPT_FILE"
|
||||||
export AI_LAUNCHER=eltex
|
export AI_LAUNCHER=eltex
|
||||||
export CLAUDE_CONFIG_DIR="$HOME/.config/ai-setup/cfg/eltex"
|
export CLAUDE_CONFIG_DIR="$HOME/.config/ai-setup/cfg/eltex"
|
||||||
# Пикер: все слоты (opus, sonnet, haiku) = glm-5.3, других моделей ai-eltex не использует.
|
# Пикер: все слоты (opus, sonnet, haiku) = anth-glm-5.3, других моделей ai-eltex не использует.
|
||||||
# Незаданный слот показал бы чужой Claude, а haiku Claude Code берёт и для фоновых задач
|
# Незаданный слот показал бы чужой Claude, а haiku Claude Code берёт и для фоновых задач
|
||||||
# вроде заголовков. availableModels НЕ задаём (он схлопывает пикер).
|
# вроде заголовков. availableModels НЕ задаём (он схлопывает пикер).
|
||||||
# Effort как у ai-glm: старт на max через CLI --effort (перебивает effortLevel из
|
# Effort как у ai-glm: старт на max через CLI --effort (перебивает effortLevel из
|
||||||
# settings.json; AI_EFFORT=max в settings Claude Code не принимает и шлёт high), /effort
|
# settings.json; AI_EFFORT=max в settings Claude Code не принимает и шлёт high), /effort
|
||||||
# в сессии работает. Z.ai учитывает output_config.effort (20.10 через /anthropic):
|
# в сессии работает. Z.ai учитывает output_config.effort (21.10): low - без размышлений,
|
||||||
# low - без размышлений, дальше medium < high < max.
|
# medium/high/max - с размышлениями.
|
||||||
# CLAUDE_CODE_ALWAYS_ENABLE_EFFORT - страховка, как в ai-glm.
|
# CLAUDE_CODE_ALWAYS_ENABLE_EFFORT - страховка, как в ai-glm.
|
||||||
# Имена-алиасы claude-* на прокси НЕ используем: claude-3-5-sonnet Claude Code считает
|
# Имена-алиасы claude-* на прокси НЕ используем: claude-3-5-sonnet Claude Code считает
|
||||||
# старым Claude 3.5 Sonnet (без effort и thinking, max_tokens=8192); у claude-5-5-sonnet
|
# старым Claude 3.5 Sonnet (без effort и thinking, max_tokens=8192); у claude-5-5-sonnet
|
||||||
@@ -1851,7 +1802,7 @@ export CLAUDE_CONFIG_DIR="$HOME/.config/ai-setup/cfg/eltex"
|
|||||||
# "You are powered by": разброс внутри одного имени больше разницы между именами).
|
# "You are powered by": разброс внутри одного имени больше разницы между именами).
|
||||||
# CLAUDE_CODE_MAX_OUTPUT_TOKENS=64000 вместо дефолтных 32000, как у ai-glm.
|
# CLAUDE_CODE_MAX_OUTPUT_TOKENS=64000 вместо дефолтных 32000, как у ai-glm.
|
||||||
# API_TIMEOUT_MS из доки админов: прокси бывает медленным.
|
# API_TIMEOUT_MS из доки админов: прокси бывает медленным.
|
||||||
# Окно glm-5.3 - 1M через [1m] (см. выше). Автокомпакт на 200K из доки админов и
|
# Окно anth-glm-5.3 - 1M через [1m] (см. выше). Автокомпакт на 200K из доки админов и
|
||||||
# CLAUDE_CODE_DISABLE_1M_CONTEXT не ставим: ctx: показывал бы занятость в ~5 раз больше
|
# CLAUDE_CODE_DISABLE_1M_CONTEXT не ставим: ctx: показывал бы занятость в ~5 раз больше
|
||||||
# реальной.
|
# реальной.
|
||||||
# ENABLE_TOOL_SEARCH НЕ включаем: на Anthropic-эндпоинте Z.ai
|
# ENABLE_TOOL_SEARCH НЕ включаем: на Anthropic-эндпоинте Z.ai
|
||||||
@@ -1868,7 +1819,7 @@ description: Удалить сохранённый ключ ai-eltex (обраб
|
|||||||
---
|
---
|
||||||
Хук не сработал: удали ~/.config/ai-setup/eltex_key вручную и перезапусти ai-eltex (или запусти AI_RESET_KEY=1 ai-eltex).
|
Хук не сработал: удали ~/.config/ai-setup/eltex_key вручную и перезапусти ai-eltex (или запусти AI_RESET_KEY=1 ai-eltex).
|
||||||
CMDEOF
|
CMDEOF
|
||||||
ANTHROPIC_BASE_URL="$eltex_base_url/anthropic" \
|
ANTHROPIC_BASE_URL="$eltex_base_url" \
|
||||||
ANTHROPIC_AUTH_TOKEN="$api_key" \
|
ANTHROPIC_AUTH_TOKEN="$api_key" \
|
||||||
ANTHROPIC_DEFAULT_OPUS_MODEL="$opus_model" \
|
ANTHROPIC_DEFAULT_OPUS_MODEL="$opus_model" \
|
||||||
ANTHROPIC_DEFAULT_OPUS_MODEL_NAME="$model" \
|
ANTHROPIC_DEFAULT_OPUS_MODEL_NAME="$model" \
|
||||||
@@ -2606,7 +2557,7 @@ echo -e " ${CYAN}ai-gpt${NC} - OpenAI Codex (нативный CLI
|
|||||||
echo -e " ${CYAN}ai-gemini${NC} - Gemini (нативный agy CLI, автоустановка)"
|
echo -e " ${CYAN}ai-gemini${NC} - Gemini (нативный agy CLI, автоустановка)"
|
||||||
echo -e " ${CYAN}ai-cursor${NC} - Cursor (нативный Cursor CLI, автоустановка)"
|
echo -e " ${CYAN}ai-cursor${NC} - Cursor (нативный Cursor CLI, автоустановка)"
|
||||||
echo ""
|
echo ""
|
||||||
echo " Android CLI:"
|
echo " Android CLI (не ставится по умолчанию):"
|
||||||
echo -e " ${CYAN}android${NC} - Google Android CLI (SDK, эмулятор, проекты)"
|
echo -e " ${CYAN}android${NC} - Google Android CLI: bash setup.sh → пункт 8"
|
||||||
echo ""
|
echo ""
|
||||||
echo -e "Чтобы команды были доступны сразу, выполните: ${GREEN}exec bash${NC}"
|
echo -e "Чтобы команды были доступны сразу, выполните: ${GREEN}exec bash${NC}"
|
||||||
|
|||||||
72
scripts/android-cli-setup.sh
Executable file
72
scripts/android-cli-setup.sh
Executable file
@@ -0,0 +1,72 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Copyright (c) 2026 Виталий Никитенко. MIT License.
|
||||||
|
# android-cli-setup.sh — установка Google Android CLI (по выбору, пункт 8 в setup.sh)
|
||||||
|
# Запуск: bash scripts/android-cli-setup.sh
|
||||||
|
|
||||||
|
# Автоопределение: ~/bin если есть в PATH, иначе ~/.local/bin
|
||||||
|
if [[ ":$PATH:" == *":$HOME/bin:"* ]]; then
|
||||||
|
BIN_DIR="$HOME/bin"
|
||||||
|
else
|
||||||
|
BIN_DIR="$HOME/.local/bin"
|
||||||
|
fi
|
||||||
|
|
||||||
|
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; CYAN='\033[0;36m'; NC='\033[0m'
|
||||||
|
info() { echo -e "${CYAN}[INFO]${NC} $*"; }
|
||||||
|
success() { echo -e "${GREEN}[OK]${NC} $*"; }
|
||||||
|
warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
|
||||||
|
|
||||||
|
# Запрет запуска от root
|
||||||
|
if [ "$EUID" -eq 0 ]; then
|
||||||
|
echo -e "${RED}Не запускайте этот скрипт через sudo!${NC}"
|
||||||
|
echo "Запустите просто: bash scripts/android-cli-setup.sh"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
info "Проверяю Android CLI..."
|
||||||
|
ANDROID_BIN="$HOME/.local/bin/android"
|
||||||
|
[ ! -f "$ANDROID_BIN" ] && ANDROID_BIN="$(command -v android 2>/dev/null || true)"
|
||||||
|
|
||||||
|
if [ -z "$ANDROID_BIN" ] || [ ! -f "$ANDROID_BIN" ]; then
|
||||||
|
info "Устанавливаю Android CLI..."
|
||||||
|
_uname_s=$(uname -s)
|
||||||
|
_uname_m=$(uname -m)
|
||||||
|
ANDROID_PLATFORM=""
|
||||||
|
case "${_uname_s}-${_uname_m}" in
|
||||||
|
Linux-x86_64) ANDROID_PLATFORM="linux_x86_64" ;;
|
||||||
|
Linux-aarch64) ANDROID_PLATFORM="linux_arm64" ;;
|
||||||
|
Linux-arm64) ANDROID_PLATFORM="linux_arm64" ;;
|
||||||
|
Darwin-x86_64) ANDROID_PLATFORM="darwin_x86_64" ;;
|
||||||
|
Darwin-arm64) ANDROID_PLATFORM="darwin_arm64" ;;
|
||||||
|
Darwin-aarch64) ANDROID_PLATFORM="darwin_arm64" ;;
|
||||||
|
MINGW*|MSYS*|CYGWIN*-x86_64) ANDROID_PLATFORM="windows_x86_64" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [ -n "$ANDROID_PLATFORM" ]; then
|
||||||
|
ANDROID_INSTALL_URL="https://dl.google.com/android/cli/latest/${ANDROID_PLATFORM}/install.sh"
|
||||||
|
if curl -fsSL "$ANDROID_INSTALL_URL" | bash; then
|
||||||
|
success "Android CLI установлен"
|
||||||
|
else
|
||||||
|
warn "Не удалось установить Android CLI через официальный скрипт"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
warn "Неизвестная платформа ${_uname_s} ${_uname_m}. Пропускаю Android CLI."
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
success "Android CLI уже установлен: $($ANDROID_BIN --version 2>/dev/null | head -1)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Официальный install.sh ставит бинарь в ~/.local/bin/android.
|
||||||
|
# Если пользователь использует ~/bin вместо ~/.local/bin - symlink.
|
||||||
|
if [ "$BIN_DIR" != "$HOME/.local/bin" ] && [ -f "$HOME/.local/bin/android" ] && [ ! -f "$BIN_DIR/android" ]; then
|
||||||
|
ln -sf "$HOME/.local/bin/android" "$BIN_DIR/android"
|
||||||
|
success "Android CLI symlink -> $BIN_DIR/android"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Разворачиваем Android CLI skills для агентов (Claude Code и др.)
|
||||||
|
if command -v android &>/dev/null; then
|
||||||
|
info "Запускаю android init для деплоя skills..."
|
||||||
|
mkdir -p "$HOME/.claude/skills"
|
||||||
|
android init || warn "android init завершился с ошибкой"
|
||||||
|
else
|
||||||
|
info "Android CLI не найден в PATH, пропускаю android init"
|
||||||
|
fi
|
||||||
4
setup.sh
4
setup.sh
@@ -107,7 +107,7 @@ else
|
|||||||
echo -e " ${GRY}git pull + перегенерация всех скриптов в ~/bin (или ~/.local/bin).${CLR}"
|
echo -e " ${GRY}git pull + перегенерация всех скриптов в ~/bin (или ~/.local/bin).${CLR}"
|
||||||
echo ""
|
echo ""
|
||||||
echo -e " ${BLD}8) Android CLI${CLR}"
|
echo -e " ${BLD}8) Android CLI${CLR}"
|
||||||
echo -e " ${GRY}Установить Google Android CLI для Android-разработки.${CLR}"
|
echo -e " ${GRY}Установить Google Android CLI для Android-разработки (пункт 1 его не ставит).${CLR}"
|
||||||
echo ""
|
echo ""
|
||||||
echo -n "Выбери [1-8] или Enter для выхода: "
|
echo -n "Выбери [1-8] или Enter для выхода: "
|
||||||
read -r choice
|
read -r choice
|
||||||
@@ -279,7 +279,7 @@ case "$choice" in
|
|||||||
do_update
|
do_update
|
||||||
;;
|
;;
|
||||||
8)
|
8)
|
||||||
bash scripts/ai-setup.sh
|
bash scripts/android-cli-setup.sh
|
||||||
;;
|
;;
|
||||||
"")
|
"")
|
||||||
exit 0
|
exit 0
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ set -euo pipefail
|
|||||||
SCRIPT="$(cd "$(dirname "$0")/.." && pwd)/scripts/ai-setup.sh"
|
SCRIPT="$(cd "$(dirname "$0")/.." && pwd)/scripts/ai-setup.sh"
|
||||||
GLOBAL_RULES_SOURCE="$(cd "$(dirname "$0")/.." && pwd)/home-configs/GLOBAL_RULES.md"
|
GLOBAL_RULES_SOURCE="$(cd "$(dirname "$0")/.." && pwd)/home-configs/GLOBAL_RULES.md"
|
||||||
ADD_HOOK="$(cd "$(dirname "$0")/.." && pwd)/home-configs/claude/hooks/add-account-hook.sh"
|
ADD_HOOK="$(cd "$(dirname "$0")/.." && pwd)/home-configs/claude/hooks/add-account-hook.sh"
|
||||||
|
ANDROID_SCRIPT="$(cd "$(dirname "$0")/.." && pwd)/scripts/android-cli-setup.sh"
|
||||||
|
SETUP_MENU="$(cd "$(dirname "$0")/.." && pwd)/setup.sh"
|
||||||
PASS=0; FAIL=0
|
PASS=0; FAIL=0
|
||||||
|
|
||||||
ok() { echo "[PASS] $1"; PASS=$((PASS+1)); }
|
ok() { echo "[PASS] $1"; PASS=$((PASS+1)); }
|
||||||
@@ -113,7 +115,7 @@ test_glm_official_api() {
|
|||||||
test_eltex_claude_launcher() {
|
test_eltex_claude_launcher() {
|
||||||
if echo "$ELTEX_SECTION" | grep -q 'claude --dangerously-skip-permissions' \
|
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 'ELTEX_BASE_URL:-http://llm.eltex.loc:4000' \
|
||||||
&& echo "$ELTEX_SECTION" | grep -q 'ANTHROPIC_BASE_URL="$eltex_base_url/anthropic"' \
|
&& 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 'CLAUDE_CONFIG_DIR="$HOME/.config/ai-setup/cfg/eltex"' \
|
||||||
&& echo "$ELTEX_SECTION" | grep -q 'key_file="$HOME/.config/ai-setup/eltex_key"'; then
|
&& 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"
|
ok "ai-eltex: launches claude via llm.eltex.loc with its own key and config dir"
|
||||||
@@ -125,19 +127,19 @@ test_eltex_claude_launcher() {
|
|||||||
# ── ai-eltex: модель берётся из /v1/models ключа ──────────────────────────
|
# ── ai-eltex: модель берётся из /v1/models ключа ──────────────────────────
|
||||||
test_eltex_model_from_key() {
|
test_eltex_model_from_key() {
|
||||||
if echo "$ELTEX_SECTION" | grep -q '/v1/models' \
|
if echo "$ELTEX_SECTION" | grep -q '/v1/models' \
|
||||||
&& echo "$ELTEX_SECTION" | grep -Fq 'model="${ELTEX_MODEL:-${model:-glm-5.3}}"' \
|
&& echo "$ELTEX_SECTION" | grep -Fq 'model="${ELTEX_MODEL:-${model:-anth-glm-5.3}}"' \
|
||||||
&& echo "$ELTEX_SECTION" | grep -Fq 'pick("glm-5.3", "glm-5.3-", "flash")' \
|
&& echo "$ELTEX_SECTION" | grep -Fq 'pick("anth-glm-5.3", "anth-glm-5.3-")' \
|
||||||
&& ! echo "$ELTEX_SECTION" | grep -q 'ids\[0\]' \
|
&& ! echo "$ELTEX_SECTION" | grep -q 'ids\[0\]' \
|
||||||
&& echo "$ELTEX_SECTION" | grep -q 'ANTHROPIC_DEFAULT_OPUS_MODEL="$opus_model"' \
|
&& echo "$ELTEX_SECTION" | grep -q 'ANTHROPIC_DEFAULT_OPUS_MODEL="$opus_model"' \
|
||||||
&& echo "$ELTEX_SECTION" | grep -q 'ANTHROPIC_DEFAULT_SONNET_MODEL="$opus_model"' \
|
&& echo "$ELTEX_SECTION" | grep -q 'ANTHROPIC_DEFAULT_SONNET_MODEL="$opus_model"' \
|
||||||
&& echo "$ELTEX_SECTION" | grep -q 'ANTHROPIC_DEFAULT_HAIKU_MODEL="$opus_model"'; then
|
&& echo "$ELTEX_SECTION" | grep -q 'ANTHROPIC_DEFAULT_HAIKU_MODEL="$opus_model"'; then
|
||||||
ok "ai-eltex: glm-5.3 by default, never the first /v1/models entry (ELTEX_MODEL overrides)"
|
ok "ai-eltex: anth-glm-5.3 by default, never the first /v1/models entry (ELTEX_MODEL overrides)"
|
||||||
else
|
else
|
||||||
fail "ai-eltex: must default to glm-5.3 (not the first /v1/models entry), ELTEX_MODEL overrides"
|
fail "ai-eltex: must default to anth-glm-5.3 (not the first /v1/models entry), ELTEX_MODEL overrides"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# ── ai-eltex: glm-5.3 во всех слотах пикера (имена с суффиксом тоже) ───────
|
# ── ai-eltex: anth-glm-5.3 во всех слотах пикера (имена с суффиксом тоже) ──
|
||||||
test_eltex_three_slots() {
|
test_eltex_three_slots() {
|
||||||
local tmp ok_run=1 out
|
local tmp ok_run=1 out
|
||||||
tmp=$(mktemp -d)
|
tmp=$(mktemp -d)
|
||||||
@@ -154,32 +156,32 @@ echo "SLOTS opus=$ANTHROPIC_DEFAULT_OPUS_MODEL sonnet=$ANTHROPIC_DEFAULT_SONNET_
|
|||||||
CLAUDEEOF
|
CLAUDEEOF
|
||||||
chmod +x "$tmp/mock/curl" "$tmp/mock/claude"
|
chmod +x "$tmp/mock/curl" "$tmp/mock/claude"
|
||||||
echo sk-test > "$tmp/home/.config/ai-setup/eltex_key"
|
echo sk-test > "$tmp/home/.config/ai-setup/eltex_key"
|
||||||
# Как на прокси: flash идёт первой, плюс имя группы доступа - во всех слотах glm-5.3
|
# Как на прокси 21.10: zai-модели идут первыми, плюс имя группы доступа
|
||||||
out=$(HOME="$tmp/home" PATH="$tmp/mock:$PATH" \
|
out=$(HOME="$tmp/home" PATH="$tmp/mock:$PATH" \
|
||||||
MODELS_BODY='{"data":[{"id":"glm-5.3-flash"},{"id":"glm-5.3"},{"id":"ZAI-Test-Group"}]}' \
|
MODELS_BODY='{"data":[{"id":"zai-glm-5.3-flash"},{"id":"anth-glm-5.3"},{"id":"zai-glm-5.3"},{"id":"ZAI-Test-Group"}]}' \
|
||||||
bash "$tmp/bin/ai-eltex" 2>&1)
|
bash "$tmp/bin/ai-eltex" 2>&1)
|
||||||
echo "$out" | grep -Fq 'SLOTS opus=glm-5.3[1m] sonnet=glm-5.3[1m] haiku=glm-5.3[1m] sub=glm-5.3[1m]' || ok_run=0
|
echo "$out" | grep -Fq 'SLOTS opus=anth-glm-5.3[1m] sonnet=anth-glm-5.3[1m] haiku=anth-glm-5.3[1m] sub=anth-glm-5.3[1m]' || ok_run=0
|
||||||
# Имена с суффиксом: модель не путается с flash
|
# Имя с суффиксом
|
||||||
out=$(HOME="$tmp/home" PATH="$tmp/mock:$PATH" \
|
out=$(HOME="$tmp/home" PATH="$tmp/mock:$PATH" \
|
||||||
MODELS_BODY='{"data":[{"id":"glm-5.3-flash-2"},{"id":"glm-5.3-2"}]}' \
|
MODELS_BODY='{"data":[{"id":"zai-glm-5.3-2"},{"id":"anth-glm-5.3-2"}]}' \
|
||||||
bash "$tmp/bin/ai-eltex" 2>&1)
|
bash "$tmp/bin/ai-eltex" 2>&1)
|
||||||
echo "$out" | grep -Fq 'SLOTS opus=glm-5.3-2[1m] sonnet=glm-5.3-2[1m] haiku=glm-5.3-2[1m]' || ok_run=0
|
echo "$out" | grep -Fq 'SLOTS opus=anth-glm-5.3-2[1m] sonnet=anth-glm-5.3-2[1m] haiku=anth-glm-5.3-2[1m]' || ok_run=0
|
||||||
if [ "$ok_run" -eq 1 ]; then
|
if [ "$ok_run" -eq 1 ]; then
|
||||||
ok "ai-eltex: glm-5.3[1m] in every picker slot, flash never picked"
|
ok "ai-eltex: anth-glm-5.3[1m] in every picker slot, zai/flash never picked"
|
||||||
else
|
else
|
||||||
fail "ai-eltex: every picker slot must be glm-5.3[1m], flash must never be picked"
|
fail "ai-eltex: every picker slot must be anth-glm-5.3[1m], zai/flash must never be picked"
|
||||||
fi
|
fi
|
||||||
rm -rf "$tmp"
|
rm -rf "$tmp"
|
||||||
}
|
}
|
||||||
|
|
||||||
# ── ai-eltex: нет glm-5.3 у ключа -> авто-логаут, свежий ключ не сохраняется ──
|
# ── ai-eltex: нет anth-glm-5.3 у ключа -> авто-логаут, свежий ключ не сохраняется ──
|
||||||
test_eltex_autologout_on_missing_model() {
|
test_eltex_autologout_on_missing_model() {
|
||||||
local tmp ok_run=1 rc=0 out
|
local tmp ok_run=1 rc=0 out
|
||||||
tmp=$(mktemp -d)
|
tmp=$(mktemp -d)
|
||||||
mkdir -p "$tmp/bin" "$tmp/mock" "$tmp/home/.config/ai-setup"
|
mkdir -p "$tmp/bin" "$tmp/mock" "$tmp/home/.config/ai-setup"
|
||||||
echo "$HELPERS_SECTION" | HELPERS_FILE="$tmp/bin/ai-api-helpers.sh" bash
|
echo "$HELPERS_SECTION" | HELPERS_FILE="$tmp/bin/ai-api-helpers.sh" bash
|
||||||
echo "$ELTEX_SECTION" | BIN_DIR="$tmp/bin" bash
|
echo "$ELTEX_SECTION" | BIN_DIR="$tmp/bin" bash
|
||||||
# Прокси отвечает 200, но glm-5.3 в списке моделей ключа нет
|
# Прокси отвечает 200, но anth-glm-5.3 в списке моделей ключа нет
|
||||||
cat > "$tmp/mock/curl" <<'CURLEOF'
|
cat > "$tmp/mock/curl" <<'CURLEOF'
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
if [[ "$*" == *"/v1/models"* ]]; then
|
if [[ "$*" == *"/v1/models"* ]]; then
|
||||||
@@ -193,16 +195,16 @@ CURLEOF
|
|||||||
# Сохранённый ключ: авто-логаут (файл удалён), новый ключ не вводим -> выход 1
|
# Сохранённый ключ: авто-логаут (файл удалён), новый ключ не вводим -> выход 1
|
||||||
echo sk-old > "$tmp/home/.config/ai-setup/eltex_key"
|
echo sk-old > "$tmp/home/.config/ai-setup/eltex_key"
|
||||||
out=$(printf 'n\n' | HOME="$tmp/home" PATH="$tmp/mock:$PATH" \
|
out=$(printf 'n\n' | HOME="$tmp/home" PATH="$tmp/mock:$PATH" \
|
||||||
MODELS_BODY='{"data":[{"id":"glm-5.3-flash-2"},{"id":"ZAI-Test-Group"}]}' \
|
MODELS_BODY='{"data":[{"id":"zai-glm-5.3-flash-2"},{"id":"ZAI-Test-Group"}]}' \
|
||||||
bash "$tmp/bin/ai-eltex" 2>&1) || rc=$?
|
bash "$tmp/bin/ai-eltex" 2>&1) || rc=$?
|
||||||
[ "$rc" -eq 1 ] || ok_run=0
|
[ "$rc" -eq 1 ] || ok_run=0
|
||||||
echo "$out" | grep -q 'Ключу недоступна модель glm-5.3' || ok_run=0
|
echo "$out" | grep -q 'Ключу недоступна модель anth-glm-5.3' || ok_run=0
|
||||||
echo "$out" | grep -q 'авто-логаут' || ok_run=0
|
echo "$out" | grep -q 'авто-логаут' || ok_run=0
|
||||||
[ ! -f "$tmp/home/.config/ai-setup/eltex_key" ] || ok_run=0
|
[ ! -f "$tmp/home/.config/ai-setup/eltex_key" ] || ok_run=0
|
||||||
# Свежий ключ без glm-5.3 не сохраняется вовсе
|
# Свежий ключ без anth-glm-5.3 не сохраняется вовсе
|
||||||
rc=0
|
rc=0
|
||||||
out=$(printf 'sk-new\n' | HOME="$tmp/home" PATH="$tmp/mock:$PATH" \
|
out=$(printf 'sk-new\n' | HOME="$tmp/home" PATH="$tmp/mock:$PATH" \
|
||||||
MODELS_BODY='{"data":[{"id":"glm-5.3-flash-2"}]}' \
|
MODELS_BODY='{"data":[{"id":"zai-glm-5.3-flash-2"}]}' \
|
||||||
bash "$tmp/bin/ai-eltex" 2>&1) || rc=$?
|
bash "$tmp/bin/ai-eltex" 2>&1) || rc=$?
|
||||||
[ "$rc" -eq 1 ] || ok_run=0
|
[ "$rc" -eq 1 ] || ok_run=0
|
||||||
echo "$out" | grep -q 'Ключ НЕ сохранён' || ok_run=0
|
echo "$out" | grep -q 'Ключ НЕ сохранён' || ok_run=0
|
||||||
@@ -211,15 +213,15 @@ CURLEOF
|
|||||||
echo sk-keep > "$tmp/home/.config/ai-setup/eltex_key"
|
echo sk-keep > "$tmp/home/.config/ai-setup/eltex_key"
|
||||||
rc=0
|
rc=0
|
||||||
out=$(HOME="$tmp/home" PATH="$tmp/mock:$PATH" \
|
out=$(HOME="$tmp/home" PATH="$tmp/mock:$PATH" \
|
||||||
MODELS_BODY='{"data":[{"id":"glm-5.3-flash-2"}]}' \
|
MODELS_BODY='{"data":[{"id":"zai-glm-5.3-flash-2"}]}' \
|
||||||
ELTEX_MODEL=glm-5.3-2 bash "$tmp/bin/ai-eltex" 2>&1) || rc=$?
|
ELTEX_MODEL=anth-glm-5.3-2 bash "$tmp/bin/ai-eltex" 2>&1) || rc=$?
|
||||||
[ "$rc" -eq 0 ] || ok_run=0
|
[ "$rc" -eq 0 ] || ok_run=0
|
||||||
echo "$out" | grep -q 'Модель: glm-5.3-2' || ok_run=0
|
echo "$out" | grep -q 'Модель: anth-glm-5.3-2' || ok_run=0
|
||||||
[ "$(cat "$tmp/home/.config/ai-setup/eltex_key")" = "sk-keep" ] || ok_run=0
|
[ "$(cat "$tmp/home/.config/ai-setup/eltex_key")" = "sk-keep" ] || ok_run=0
|
||||||
if [ "$ok_run" -eq 1 ]; then
|
if [ "$ok_run" -eq 1 ]; then
|
||||||
ok "ai-eltex: missing glm-5.3 auto-logouts saved key, fresh key not saved, ELTEX_MODEL bypasses"
|
ok "ai-eltex: missing anth-glm-5.3 auto-logouts saved key, fresh key not saved, ELTEX_MODEL bypasses"
|
||||||
else
|
else
|
||||||
fail "ai-eltex: missing glm-5.3 must auto-logout (saved key removed, fresh key not saved, ELTEX_MODEL bypass)"
|
fail "ai-eltex: missing anth-glm-5.3 must auto-logout (saved key removed, fresh key not saved, ELTEX_MODEL bypass)"
|
||||||
fi
|
fi
|
||||||
rm -rf "$tmp"
|
rm -rf "$tmp"
|
||||||
}
|
}
|
||||||
@@ -235,13 +237,13 @@ test_eltex_no_tool_search() {
|
|||||||
|
|
||||||
# ── ai-eltex: окно 1M, как у ai-glm (иначе ctx: завышен в ~5 раз) ─────────
|
# ── ai-eltex: окно 1M, как у ai-glm (иначе ctx: завышен в ~5 раз) ─────────
|
||||||
test_eltex_context_window() {
|
test_eltex_context_window() {
|
||||||
if echo "$ELTEX_SECTION" | grep -Fq 'glm-5.3*) opus_model="${model}[1m]"' \
|
if echo "$ELTEX_SECTION" | grep -Fq 'anth-glm-5.3*) opus_model="${model}[1m]"' \
|
||||||
&& ! echo "$ELTEX_SECTION" | grep -q '^CLAUDE_CODE_MAX_CONTEXT_TOKENS=' \
|
&& ! echo "$ELTEX_SECTION" | grep -q '^CLAUDE_CODE_MAX_CONTEXT_TOKENS=' \
|
||||||
&& ! echo "$ELTEX_SECTION" | grep -q '^CLAUDE_CODE_DISABLE_1M_CONTEXT=' \
|
&& ! echo "$ELTEX_SECTION" | grep -q '^CLAUDE_CODE_DISABLE_1M_CONTEXT=' \
|
||||||
&& ! echo "$ELTEX_SECTION" | grep -q '^CLAUDE_CODE_AUTO_COMPACT_WINDOW='; then
|
&& ! echo "$ELTEX_SECTION" | grep -q '^CLAUDE_CODE_AUTO_COMPACT_WINDOW='; then
|
||||||
ok "ai-eltex: 1M window for glm-5.3 via [1m], no global MAX_CONTEXT / DISABLE_1M"
|
ok "ai-eltex: 1M window for anth-glm-5.3 via [1m], no global MAX_CONTEXT / DISABLE_1M"
|
||||||
else
|
else
|
||||||
fail "ai-eltex: 1M for glm-5.3 via [1m], no global CLAUDE_CODE_MAX_CONTEXT_TOKENS / DISABLE_1M / AUTO_COMPACT_WINDOW"
|
fail "ai-eltex: 1M for anth-glm-5.3 via [1m], no global CLAUDE_CODE_MAX_CONTEXT_TOKENS / DISABLE_1M / AUTO_COMPACT_WINDOW"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -555,9 +557,33 @@ test_script_syntax() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# ── Android CLI: install block exists ─────────────────────────────────────
|
# ── Android CLI: opt-in install (setup.sh item 8), not part of ai-setup.sh ─
|
||||||
|
test_android_script_syntax() {
|
||||||
|
if bash -n "$ANDROID_SCRIPT" 2>&1; then
|
||||||
|
ok "android-cli: android-cli-setup.sh passes 'bash -n'"
|
||||||
|
else
|
||||||
|
fail "android-cli: android-cli-setup.sh has syntax errors"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
test_android_not_installed_by_default() {
|
||||||
|
if ! grep -q 'dl.google.com/android/cli' "$SCRIPT" && ! grep -q 'android init' "$SCRIPT"; then
|
||||||
|
ok "android-cli: ai-setup.sh does not install Android CLI by default"
|
||||||
|
else
|
||||||
|
fail "android-cli: ai-setup.sh still installs Android CLI"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
test_android_menu_item_runs_script() {
|
||||||
|
if awk '/^ 8\)/,/;;/' "$SETUP_MENU" | grep -q 'bash scripts/android-cli-setup.sh'; then
|
||||||
|
ok "android-cli: setup.sh item 8 runs android-cli-setup.sh"
|
||||||
|
else
|
||||||
|
fail "android-cli: setup.sh item 8 does not run android-cli-setup.sh"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
test_android_cli_install_url() {
|
test_android_cli_install_url() {
|
||||||
if grep -q 'dl.google.com/android/cli/latest' "$SCRIPT"; then
|
if grep -q 'dl.google.com/android/cli/latest' "$ANDROID_SCRIPT"; then
|
||||||
ok "android-cli: install URL for Android CLI is present"
|
ok "android-cli: install URL for Android CLI is present"
|
||||||
else
|
else
|
||||||
fail "android-cli: missing install URL for Android CLI"
|
fail "android-cli: missing install URL for Android CLI"
|
||||||
@@ -565,7 +591,7 @@ test_android_cli_install_url() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test_android_init_called() {
|
test_android_init_called() {
|
||||||
if grep -q 'android init' "$SCRIPT"; then
|
if grep -q 'android init' "$ANDROID_SCRIPT"; then
|
||||||
ok "android-cli: android init is invoked after install"
|
ok "android-cli: android init is invoked after install"
|
||||||
else
|
else
|
||||||
fail "android-cli: missing android init invocation"
|
fail "android-cli: missing android init invocation"
|
||||||
@@ -573,7 +599,7 @@ test_android_init_called() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test_android_symlink_to_bin_dir() {
|
test_android_symlink_to_bin_dir() {
|
||||||
if grep -q 'ln -sf "$HOME/.local/bin/android" "$BIN_DIR/android"' "$SCRIPT"; then
|
if grep -q 'ln -sf "$HOME/.local/bin/android" "$BIN_DIR/android"' "$ANDROID_SCRIPT"; then
|
||||||
ok "android-cli: symlink to BIN_DIR is handled"
|
ok "android-cli: symlink to BIN_DIR is handled"
|
||||||
else
|
else
|
||||||
fail "android-cli: missing symlink to BIN_DIR"
|
fail "android-cli: missing symlink to BIN_DIR"
|
||||||
@@ -702,6 +728,9 @@ test_global_rules_source_installed
|
|||||||
test_native_rule_files_generated
|
test_native_rule_files_generated
|
||||||
test_codex_sound_hooks_detach_stdio
|
test_codex_sound_hooks_detach_stdio
|
||||||
test_fix7_trap_tmp
|
test_fix7_trap_tmp
|
||||||
|
test_android_script_syntax
|
||||||
|
test_android_not_installed_by_default
|
||||||
|
test_android_menu_item_runs_script
|
||||||
test_android_cli_install_url
|
test_android_cli_install_url
|
||||||
test_android_init_called
|
test_android_init_called
|
||||||
test_android_symlink_to_bin_dir
|
test_android_symlink_to_bin_dir
|
||||||
|
|||||||
Reference in New Issue
Block a user