feat(qwen): add ai-qwen launcher for Alibaba Token Plan (Qwen3.8)

ai-qwen runs Claude Code through Alibaba Cloud Model Studio's
Anthropic-compatible Token Plan endpoint
(token-plan.ap-southeast-1.maas.aliyuncs.com/apps/anthropic). The shared
key is built into the generated script, so it starts right away without
asking for a key.

qwen3.8-max (the smartest model the key has) is in opus/sonnet and for
subagents, --model opus on each start; qwen3.8-flash is in haiku for
background tasks. Measured on 20.10: both models accept up to 983616
input tokens (CLAUDE_CODE_MAX_CONTEXT_TOKENS=1000000, autocompact fires
before the API limit) and see images. Qwen validates
output_config.effort (bogus -> 400), Max shows no trend from low to
max, Flash thinks ~2x longer on max; the launcher starts on --effort max
like ai-mimo, EFFORT_MAPPING.md records the measurements.

setup.sh status, statusline brand color, README, QUICK_START and
AGENTS.md list the new launcher.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Виталий Никитенко
2026-10-20 12:01:31 +07:00
parent 41c5cf9b10
commit 0502478081
8 changed files with 119 additions and 10 deletions

View File

@@ -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-eltex`, `ai-eltex-qwen`, `ai-mimo`, `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-eltex-qwen`, `ai-mimo`, `ai-qwen`, `ai-openrouter`, `ai-gemini`, `ai-api-helpers.sh`, `ai-claude`, `claude-gpt-effort-proxy.py`) должны быть **полностью перезаписаны** актуальными версиями. Запрещено выполнять слияние (merge) старого и нового содержимого или дополнение (append). Скрипт обязан привести все генерируемые файлы к эталонному виду, однозначно определяемому текущей конфигурацией.

View File

@@ -3,7 +3,7 @@
## Как это работает ## Как это работает
`/effort` и `AI_EFFORT` относятся к лаунчерам, которые запускают Claude Code: `/effort` и `AI_EFFORT` относятся к лаунчерам, которые запускают Claude Code:
`ai-claude`, `ai-deepseek`, `ai-kimi`, `ai-glm`, `ai-mimo`, `ai-openrouter`, `ai-opencode`. `ai-claude`, `ai-deepseek`, `ai-kimi`, `ai-glm`, `ai-mimo`, `ai-qwen`, `ai-openrouter`, `ai-opencode`.
Нативные лаунчеры `ai-gpt` (OpenAI Codex), `ai-gemini` (Antigravity `agy`) и `ai-cursor` Нативные лаунчеры `ai-gpt` (OpenAI Codex), `ai-gemini` (Antigravity `agy`) и `ai-cursor`
(Cursor CLI `agent`) не используют эту схему. У них свои настройки reasoning внутри (Cursor CLI `agent`) не используют эту схему. У них свои настройки reasoning внутри
@@ -128,6 +128,22 @@ thinking on (единственный уровень)
- Дефолт `ai-mimo`: `max`, задаётся через CLI `--effort` при каждом запуске (как у `ai-eltex-qwen`). - Дефолт `ai-mimo`: `max`, задаётся через CLI `--effort` при каждом запуске (как у `ai-eltex-qwen`).
На размышления не влияет, но если Xiaomi начнёт учитывать effort, лаунчер сразу будет на максимуме. На размышления не влияет, но если Xiaomi начнёт учитывать effort, лаунчер сразу будет на максимуме.
### Qwen3.8 (Alibaba Token Plan)
```text
low -> medium -> high -> xhigh -> max (принимаются, у Max тренда нет)
```
- `ai-qwen` работает через Claude Code с Anthropic-эндпоинтом Alibaba Model Studio
(`token-plan.ap-southeast-1.maas.aliyuncs.com/apps/anthropic`).
- Qwen проверяет `output_config.effort`: `bogus` даёт HTTP 400 со списком
`low, medium, high, xhigh, max`. `thinking.type=adaptive` принимается, размышления есть всегда.
- Замер 2026-10-20, задача на включения-исключения, `output_tokens`. `qwen3.8-max`, по 3 запроса:
`low` 435/513/615, `high` 363/412/662, `max` 397/539/657 - разброс больше разницы, тренда нет.
`qwen3.8-flash`, по 2 запроса: `low` ~430, `max` ~790.
- Дефолт `ai-qwen`: `max` через CLI `--effort` при каждом запуске, `CLAUDE_CODE_ALWAYS_ENABLE_EFFORT=1`
как страховка.
`claude-gpt-effort-proxy.py` все еще генерируется как совместимый helper для старого `claude-gpt-effort-proxy.py` все еще генерируется как совместимый helper для старого
`claude-code-proxy` backend-а. Если использовать его вручную, он маппит только `claude-code-proxy` backend-а. Если использовать его вручную, он маппит только
`xhigh` -> `high`, потому что `claude-code-proxy` принимает `low`, `medium`, `high`, `max`. `xhigh` -> `high`, потому что `claude-code-proxy` принимает `low`, `medium`, `high`, `max`.
@@ -141,13 +157,14 @@ thinking on (единственный уровень)
| Kimi K2.7/K2.6 | Moonshot API | На стороне сервера | | Kimi K2.7/K2.6 | Moonshot API | На стороне сервера |
| GLM 5.3 | Z.ai API (`low,medium→low`, `high,xhigh→high`, `max`) | На стороне сервера | | GLM 5.3 | Z.ai API (`low,medium→low`, `high,xhigh→high`, `max`) | На стороне сервера |
| Xiaomi MiMo V2.6 | Не маппится: MiMo принимает `output_config.effort`, но игнорирует его | - | | Xiaomi MiMo V2.6 | Не маппится: MiMo принимает `output_config.effort`, но игнорирует его | - |
| Qwen3.8 | Alibaba API, значение уходит как есть | На стороне сервера |
| OpenRouter/GPT-5.5 | Локального маппинга нет | `ai-openrouter` отправляет значение как есть | | OpenRouter/GPT-5.5 | Локального маппинга нет | `ai-openrouter` отправляет значение как есть |
| OpenCode Go | Локального маппинга нет | `ai-opencode` отправляет значение через routatic-proxy | | OpenCode Go | Локального маппинга нет | `ai-opencode` отправляет значение через routatic-proxy |
| Legacy GPT proxy | helper-маппинг `xhigh` -> `high` | `~/bin/claude-gpt-effort-proxy.py` или `~/.local/bin/claude-gpt-effort-proxy.py` | | Legacy GPT proxy | helper-маппинг `xhigh` -> `high` | `~/bin/claude-gpt-effort-proxy.py` или `~/.local/bin/claude-gpt-effort-proxy.py` |
## Persistence effort между сессиями ## Persistence effort между сессиями
Каждый Claude Code лаунчер (`ai-claude`, `ai-deepseek`, `ai-kimi`, `ai-glm`, `ai-mimo`, `ai-openrouter`, `ai-opencode`) Каждый Claude Code лаунчер (`ai-claude`, `ai-deepseek`, `ai-kimi`, `ai-glm`, `ai-mimo`, `ai-qwen`, `ai-openrouter`, `ai-opencode`)
запоминает свой уровень effort отдельно в `settings.json` лаунчера. запоминает свой уровень effort отдельно в `settings.json` лаунчера.
`/effort` внутри сессии работает для всех уровней. `CLAUDE_CODE_EFFORT_LEVEL` не используется. `/effort` внутри сессии работает для всех уровней. `CLAUDE_CODE_EFFORT_LEVEL` не используется.
@@ -160,8 +177,8 @@ AI_EFFORT=high ai-deepseek # включить high
ai-deepseek # без флага - использовать уровень из settings.json ai-deepseek # без флага - использовать уровень из settings.json
``` ```
Дефолты: `xhigh` для `ai-claude` и `ai-glm`, `max` для `ai-eltex`, `ai-eltex-qwen` и `ai-mimo`, `high` для Дефолты: `xhigh` для `ai-claude` и `ai-glm`, `max` для `ai-eltex`, `ai-eltex-qwen`, `ai-mimo` и `ai-qwen`, `high` для
остальных Claude Code лаунчеров. `ai-glm`, `ai-eltex`, `ai-eltex-qwen` и `ai-mimo` передают уровень через CLI остальных Claude Code лаунчеров. `ai-glm`, `ai-eltex`, `ai-eltex-qwen`, `ai-mimo` и `ai-qwen` передают уровень через CLI
`--effort`, поэтому каждый запуск стартует на дефолте (или на `AI_EFFORT`), а `/effort` внутри сессии `--effort`, поэтому каждый запуск стартует на дефолте (или на `AI_EFFORT`), а `/effort` внутри сессии
действует до её конца. действует до её конца.

View File

@@ -7,7 +7,7 @@ bash setup.sh
``` ```
Установит лаунчеры Установит лаунчеры
`ai-claude`, `ai-gpt`, `ai-deepseek`, `ai-kimi`, `ai-glm`, `ai-eltex`, `ai-eltex-qwen`, `ai-mimo`, `ai-openrouter`, `ai-opencode`, `ai-gemini`, `ai-cursor` `ai-claude`, `ai-gpt`, `ai-deepseek`, `ai-kimi`, `ai-glm`, `ai-eltex`, `ai-eltex-qwen`, `ai-mimo`, `ai-qwen`, `ai-openrouter`, `ai-opencode`, `ai-gemini`, `ai-cursor`
в `~/bin`, если он уже есть в `PATH`, иначе в `~/.local/bin/`, и запишет API-ключи. в `~/bin`, если он уже есть в `PATH`, иначе в `~/.local/bin/`, и запишет API-ключи.
После установки, если команды не видны: После установки, если команды не видны:

View File

@@ -164,6 +164,7 @@ bash tests/test_network.sh # полные тесты
- `ai-eltex` - Claude Code через корпоративный LLM-прокси Eltex (`http://llm.eltex.loc:4000`, LiteLLM, team-подписка GLM). Ключ выдают админы ([дока](https://intdocs.eltex.loc/pages/viewpage.action?pageId=262329878)), три модели в `/model`: `anth-glm-5.3` по умолчанию (Anthropic-эндпоинт Z.ai: картинки, effort, окно 1M), `zai-glm-5.3` (OpenAI-эндпоинт: без картинок и effort, 200K) и `zai-glm-5.3-flash` (быстрая, картинки видит сама, 200K); если ключу недоступна `anth-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)), три модели в `/model`: `anth-glm-5.3` по умолчанию (Anthropic-эндпоинт Z.ai: картинки, effort, окно 1M), `zai-glm-5.3` (OpenAI-эндпоинт: без картинок и effort, 200K) и `zai-glm-5.3-flash` (быстрая, картинки видит сама, 200K); если ключу недоступна `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-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`
@@ -232,7 +233,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-eltex`, `ai-eltex-qwen`, `ai-mimo`, `ai-openrouter`, `ai-opencode`, `ai-gemini` используют `--dangerously-skip-permissions` - `ai-claude`, `ai-deepseek`, `ai-kimi`, `ai-glm`, `ai-eltex`, `ai-eltex-qwen`, `ai-mimo`, `ai-qwen`, `ai-openrouter`, `ai-opencode`, `ai-gemini` используют `--dangerously-skip-permissions`
- `ai-cursor` использует `--force` (алиас `--yolo`) - `ai-cursor` использует `--force` (алиас `--yolo`)
Удобно для локального coding workflow, но это не sandbox для недоверенного кода. Удобно для локального coding workflow, но это не sandbox для недоверенного кода.

View File

@@ -40,6 +40,7 @@ _brand_color() {
kimi) printf '\033[38;5;81m' ;; # Kimi голубой kimi) printf '\033[38;5;81m' ;; # Kimi голубой
glm) printf '\033[38;5;223m' ;; # Z.ai кремовый (бренд-фон z.ai, #FFE4B5) glm) printf '\033[38;5;223m' ;; # Z.ai кремовый (бренд-фон z.ai, #FFE4B5)
mimo) printf '\033[38;5;202m' ;; # Xiaomi оранжевый (#FF6900) mimo) printf '\033[38;5;202m' ;; # Xiaomi оранжевый (#FF6900)
qwen) printf '\033[38;5;99m' ;; # Qwen фиолетовый (#615CED)
openrouter) printf '\033[38;5;135m' ;; # OpenRouter фиолетовый openrouter) printf '\033[38;5;135m' ;; # OpenRouter фиолетовый
*) printf '\033[38;5;223m' ;; # кремовый (fallback) *) printf '\033[38;5;223m' ;; # кремовый (fallback)
esac esac

View File

@@ -2219,6 +2219,54 @@ claude --dangerously-skip-permissions --model opus --effort "${AI_EFFORT:-max}"
MIMOEOF MIMOEOF
chmod +x "$BIN_DIR/ai-mimo" chmod +x "$BIN_DIR/ai-mimo"
# === ai-qwen ===
cat > "$BIN_DIR/ai-qwen" << 'QWENEOF'
#!/usr/bin/env bash
# ai-qwen - запуск Claude Code через Alibaba Cloud Model Studio (Qwen 3.8, Token Plan,
# Anthropic-compatible API). Ключ общий и вшит в скрипт: запускается сразу, без ввода ключа.
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/ai-api-helpers.sh" 2>/dev/null || true
qwen_base_url="https://token-plan.ap-southeast-1.maas.aliyuncs.com/apps/anthropic"
api_key="sk-sp-H.LEDIL.UJfr.MEUCIBmN5Rtjyn9iKPnhw2sym_1auFL4YZ4tnJh54TurNMo8AiEA1SbkS2Gt872ncq-32xK2ZxlpZxS3ldNHnTgX6dNCIok"
_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=qwen
export CLAUDE_CONFIG_DIR="$HOME/.config/ai-setup/cfg/qwen"
# Модели (список ключа: .../compatible-mode/v1/models): qwen3.8-max - самая умная, она в
# opus/sonnet и в сабагентах; haiku = qwen3.8-flash (быстрая, Claude Code берёт слот haiku
# и для фоновых задач вроде заголовков - так дешевле для лимита Token Plan).
# availableModels НЕ задаём (он схлопывает пикер). --model opus при каждом запуске, как в ai-mimo.
# Окно: у обеих моделей вход до 983616 токенов (замер 20.10: ответ "Range of input length
# should be [1, 983616]"). qwen3.8-* нет в реестре Claude Code, без
# CLAUDE_CODE_MAX_CONTEXT_TOKENS окно считалось бы = 200K. Автокомпакт с окном 1000000
# срабатывает раньше предела API. Картинки обе модели видят сами.
# Effort Qwen проверяет (bogus -> 400, low/medium/high/xhigh/max принимаются), но у Max тренда
# нет, у Flash max размышляет почти вдвое дольше low (см. EFFORT_MAPPING.md). Стартуем на max
# через CLI --effort, как ai-mimo. CLAUDE_CODE_ALWAYS_ENABLE_EFFORT - страховка, как в ai-glm.
# CLAUDE_CODE_MAX_OUTPUT_TOKENS=64000 вместо дефолтных 32000, как у ai-glm.
_setup_isolated_config qwen opus high ''
ANTHROPIC_BASE_URL="$qwen_base_url" \
ANTHROPIC_AUTH_TOKEN="$api_key" \
ANTHROPIC_DEFAULT_OPUS_MODEL=qwen3.8-max \
ANTHROPIC_DEFAULT_OPUS_MODEL_NAME="Qwen3.8 Max" \
ANTHROPIC_DEFAULT_OPUS_MODEL_DESCRIPTION="Qwen3.8 Max - флагман Alibaba для сложных задач" \
ANTHROPIC_DEFAULT_SONNET_MODEL=qwen3.8-max \
ANTHROPIC_DEFAULT_SONNET_MODEL_NAME="Qwen3.8 Max" \
ANTHROPIC_DEFAULT_SONNET_MODEL_DESCRIPTION="Qwen3.8 Max - флагман Alibaba для сложных задач" \
ANTHROPIC_DEFAULT_HAIKU_MODEL=qwen3.8-flash \
ANTHROPIC_DEFAULT_HAIKU_MODEL_NAME="Qwen3.8 Flash" \
ANTHROPIC_DEFAULT_HAIKU_MODEL_DESCRIPTION="Qwen3.8 Flash - быстрая" \
CLAUDE_CODE_SUBAGENT_MODEL=qwen3.8-max \
CLAUDE_CODE_MAX_CONTEXT_TOKENS=1000000 \
CLAUDE_CODE_MAX_OUTPUT_TOKENS=64000 \
CLAUDE_CODE_ALWAYS_ENABLE_EFFORT=1 \
CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1 \
claude --dangerously-skip-permissions --model opus --effort "${AI_EFFORT:-max}" --system-prompt-file "$_PROMPT_FILE" "$@"
QWENEOF
chmod +x "$BIN_DIR/ai-qwen"
# === ai-openrouter === # === ai-openrouter ===
cat > "$BIN_DIR/ai-openrouter" << 'OPENROUTEREOF' cat > "$BIN_DIR/ai-openrouter" << 'OPENROUTEREOF'
#!/usr/bin/env bash #!/usr/bin/env bash
@@ -2523,6 +2571,7 @@ _setup_isolated_config glm opus xhigh ''
_setup_isolated_config eltex opus xhigh '' _setup_isolated_config eltex opus xhigh ''
_setup_isolated_config eltex-qwen opus high '' _setup_isolated_config eltex-qwen opus high ''
_setup_isolated_config mimo opus high '' _setup_isolated_config mimo opus high ''
_setup_isolated_config qwen 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 ''
@@ -2533,7 +2582,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-eltex" "$HOME/.local/bin/ai-eltex-qwen" "$HOME/.local/bin/ai-mimo" "$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-eltex-qwen" "$HOME/.local/bin/ai-mimo" "$HOME/.local/bin/ai-qwen" "$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
@@ -2556,6 +2605,7 @@ echo -e " ${CYAN}ai-glm${NC} - GLM 5.3 (через Claude Code, Z
echo -e " ${CYAN}ai-eltex${NC} - Корпоративный LLM-прокси Eltex (через Claude Code, ключ от админов)" echo -e " ${CYAN}ai-eltex${NC} - Корпоративный LLM-прокси Eltex (через Claude Code, ключ от админов)"
echo -e " ${CYAN}ai-eltex-qwen${NC} - Корпоративный LLM-прокси Eltex, модели Qwen (через Claude Code, свой ключ)" echo -e " ${CYAN}ai-eltex-qwen${NC} - Корпоративный LLM-прокси Eltex, модели Qwen (через Claude Code, свой ключ)"
echo -e " ${CYAN}ai-mimo${NC} - Xiaomi MiMo V2.6 Pro, максимум рассуждений (через Claude Code, Token Plan)" echo -e " ${CYAN}ai-mimo${NC} - Xiaomi MiMo V2.6 Pro, максимум рассуждений (через Claude Code, Token Plan)"
echo -e " ${CYAN}ai-qwen${NC} - Qwen3.8 Max (через Claude Code, Alibaba Token Plan, ключ встроен)"
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 ""

View File

@@ -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-eltex ai-eltex-qwen ai-mimo ai-openrouter ai-opencode ai-gemini android; do for cmd in ai-claude ai-gpt ai-deepseek ai-kimi ai-glm ai-eltex ai-eltex-qwen ai-mimo ai-qwen 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
@@ -252,7 +252,7 @@ case "$choice" in
echo "" echo ""
echo -e "${BLD}API доступность:${CLR}" echo -e "${BLD}API доступность:${CLR}"
for entry in "Anthropic:api.anthropic.com" "DeepSeek:api.deepseek.com" "OpenAI:api.openai.com" "Kimi:api.kimi.com" "GLM:api.z.ai" "MiMo:api.xiaomimimo.com" "OpenRouter:openrouter.ai" "OpenCode:opencode.ai"; do for entry in "Anthropic:api.anthropic.com" "DeepSeek:api.deepseek.com" "OpenAI:api.openai.com" "Kimi:api.kimi.com" "GLM:api.z.ai" "MiMo:api.xiaomimimo.com" "Qwen:token-plan.ap-southeast-1.maas.aliyuncs.com" "OpenRouter:openrouter.ai" "OpenCode:opencode.ai"; do
_name="${entry%%:*}" _name="${entry%%:*}"
_host="${entry##*:}" _host="${entry##*:}"
_ms=$(curl -s -o /dev/null -w "%{time_connect}" --max-time 5 "https://$_host" 2>/dev/null) _ms=$(curl -s -o /dev/null -w "%{time_connect}" --max-time 5 "https://$_host" 2>/dev/null)

View File

@@ -20,6 +20,7 @@ GLM_SECTION=$(awk '/^cat > "\$BIN_DIR\/ai-glm"/,/^GLMEOF/' "$SCRIPT")
ELTEX_SECTION=$(awk '/^cat > "\$BIN_DIR\/ai-eltex"/,/^ELTEXEOF/' "$SCRIPT") ELTEX_SECTION=$(awk '/^cat > "\$BIN_DIR\/ai-eltex"/,/^ELTEXEOF/' "$SCRIPT")
ELTEX_QWEN_SECTION=$(awk '/^cat > "\$BIN_DIR\/ai-eltex-qwen"/,/^ELTEXQWENEOF/' "$SCRIPT") ELTEX_QWEN_SECTION=$(awk '/^cat > "\$BIN_DIR\/ai-eltex-qwen"/,/^ELTEXQWENEOF/' "$SCRIPT")
MIMO_SECTION=$(awk '/^cat > "\$BIN_DIR\/ai-mimo"/,/^MIMOEOF/' "$SCRIPT") MIMO_SECTION=$(awk '/^cat > "\$BIN_DIR\/ai-mimo"/,/^MIMOEOF/' "$SCRIPT")
QWEN_SECTION=$(awk '/^cat > "\$BIN_DIR\/ai-qwen"/,/^QWENEOF/' "$SCRIPT")
LOGOUT_HOOK="$(cd "$(dirname "$0")/.." && pwd)/home-configs/claude/hooks/logout-account-hook.sh" 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")
@@ -431,6 +432,43 @@ test_logout_mimo() {
rm -rf "$tmp_home" rm -rf "$tmp_home"
} }
# ── ai-qwen: Claude Code через Alibaba Token Plan, ключ вшит ───────────────
test_qwen_launcher() {
if echo "$QWEN_SECTION" | grep -q 'CLAUDE_CONFIG_DIR="$HOME/.config/ai-setup/cfg/qwen"' \
&& echo "$QWEN_SECTION" | grep -q '^ANTHROPIC_BASE_URL="$qwen_base_url"' \
&& echo "$QWEN_SECTION" | grep -q '^ANTHROPIC_DEFAULT_OPUS_MODEL=qwen3.8-max' \
&& echo "$QWEN_SECTION" | grep -q '^ANTHROPIC_DEFAULT_SONNET_MODEL=qwen3.8-max' \
&& echo "$QWEN_SECTION" | grep -q '^ANTHROPIC_DEFAULT_HAIKU_MODEL=qwen3.8-flash' \
&& echo "$QWEN_SECTION" | grep -q '^CLAUDE_CODE_SUBAGENT_MODEL=qwen3.8-max' \
&& echo "$QWEN_SECTION" | grep -q '^CLAUDE_CODE_MAX_CONTEXT_TOKENS=1000000' \
&& echo "$QWEN_SECTION" | grep -q -- 'claude --dangerously-skip-permissions --model opus --effort "${AI_EFFORT:-max}"'; then
ok "ai-qwen: own config, qwen3.8-max in opus/sonnet/subagents, flash in haiku, 1M window, effort max"
else
fail "ai-qwen: must use cfg/qwen, qwen3.8-max/flash slots, 1M window, --model opus and --effort max"
fi
}
# ── ai-qwen: стартует сразу со вшитым ключом, ничего не спрашивая ─────────
test_qwen_starts_without_prompt() {
local tmp url token ok_run=1
tmp=$(mktemp -d)
mkdir -p "$tmp/bin" "$tmp/mock" "$tmp/home"
echo "$HELPERS_SECTION" | HELPERS_FILE="$tmp/bin/ai-api-helpers.sh" bash
echo "$QWEN_SECTION" | BIN_DIR="$tmp/bin" bash
printf '#!/usr/bin/env bash\necho "$ANTHROPIC_BASE_URL $ANTHROPIC_AUTH_TOKEN" > "%s/claude.env"\n' "$tmp" > "$tmp/mock/claude"
chmod +x "$tmp/mock/claude"
(cd "$tmp" && HOME="$tmp/home" PATH="$tmp/mock:$PATH" AI_EFFORT= bash "$tmp/bin/ai-qwen" </dev/null >/dev/null 2>&1) || ok_run=0
read -r url token < "$tmp/claude.env" 2>/dev/null || ok_run=0
[ "${url:-}" = "https://token-plan.ap-southeast-1.maas.aliyuncs.com/apps/anthropic" ] || ok_run=0
case "${token:-}" in sk-sp-?*) ;; *) ok_run=0 ;; esac
if [ "$ok_run" -eq 1 ]; then
ok "ai-qwen: starts Claude Code with the built-in endpoint and key, no prompt"
else
fail "ai-qwen: must start Claude Code right away with the built-in Token Plan endpoint and sk-sp- key"
fi
rm -rf "$tmp"
}
# ── 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}"' \
@@ -656,6 +694,8 @@ test_mimo_launcher
test_mimo_region_probe test_mimo_region_probe
test_mimo_effort test_mimo_effort
test_logout_mimo test_logout_mimo
test_qwen_launcher
test_qwen_starts_without_prompt
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