feat: полная изоляция моделей между ai-* и гибридный persistence effort
Раньше все ai-* лаунчеры делили один ~/.claude и общий settings.json, из-за чего кастомная модель (openai/gpt-5.5) из ai-openrouter протекала в пикер ai-claude. Теперь каждый сторонний провайдер изолирован в своём CLAUDE_CONFIG_DIR (~/.config/ai-setup/cfg/<launcher>) - свои settings.json и .claude.json, ноль протечек. ai-claude остаётся на ~/.claude (нативный логин). Пикеры /model приведены к требуемому виду: - ai-deepseek: только DeepSeek V4 Pro (opus) и DeepSeek V4 Flash (haiku), дефолт Pro; через availableModels + ANTHROPIC_DEFAULT_*_MODEL_NAME - ai-kimi: только Kimi K2.6 (opus) - ai-claude: только нативные модели Claude Общие skills и CLAUDE.md шарятся симлинком из ~/.claude. Persistence effort - гибрид: - low/medium/high/xhigh живут нативно в settings.json лаунчера, /effort внутри сессии работает свободно и уровень сохраняется - max нельзя сохранить в settings.json (session-only), поэтому он восстанавливается через CLAUDE_CODE_EFFORT_LEVEL; в такой max-сессии /effort залочен (ограничение Claude Code), выход - AI_EFFORT=<lvl> ai-* Текущий уровень ловит статусбар в ~/.cache/ai-setup/effort_<launcher>. Удалён устаревший effort-save-hook (заменён нативным persistence + гибридом), почищен из ~/.claude/settings.json и осиротевший кэш model_*. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -83,8 +83,34 @@ MINIMAL → LOW → MEDIUM → HIGH
|
|||||||
| Kimi K2.6 | Moonshot API | На стороне сервера |
|
| Kimi K2.6 | Moonshot API | На стороне сервера |
|
||||||
| Gemini 3.x | antigravity-claude-proxy | npm пакет |
|
| Gemini 3.x | antigravity-claude-proxy | npm пакет |
|
||||||
|
|
||||||
|
## Persistence effort между сессиями
|
||||||
|
|
||||||
|
Каждый лаунчер (`ai-claude`, `ai-deepseek`, `ai-kimi`, `ai-openrouter`) запоминает свой
|
||||||
|
уровень effort отдельно. Логика гибридная:
|
||||||
|
|
||||||
|
- **`low` / `medium` / `high` / `xhigh`** живут нативно в `settings.json` лаунчера.
|
||||||
|
`/effort` внутри сессии работает как обычно, уровень сохраняется между сессиями.
|
||||||
|
- **`max`** — единственный, который Claude Code **не сохраняет** в `settings.json`
|
||||||
|
(он session-only). Поэтому его восстанавливаем через `CLAUDE_CODE_EFFORT_LEVEL`.
|
||||||
|
Текущий уровень (включая `max`) статусбар пишет в `~/.cache/ai-setup/effort_<launcher>`.
|
||||||
|
|
||||||
|
**Важное следствие (только для `max`):** когда восстановлена `max`-сессия, выставлена
|
||||||
|
`CLAUDE_CODE_EFFORT_LEVEL=max`, и `/effort` внутри неё **не сменит** уровень
|
||||||
|
(env-переменная — жёсткий override Claude Code). На остальных уровнях `/effort` свободен.
|
||||||
|
|
||||||
|
**Как выйти из `max` (или форсить любой уровень):** перезапусти лаунчер с `AI_EFFORT`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
AI_EFFORT=max ai-deepseek # включить и запомнить max
|
||||||
|
AI_EFFORT=high ai-deepseek # вернуться на high (выйти из max)
|
||||||
|
ai-deepseek # без флага - восстанавливает последний уровень
|
||||||
|
```
|
||||||
|
|
||||||
|
Дефолты при пустом кэше: `xhigh` для `ai-claude`, `high` для остальных.
|
||||||
|
|
||||||
## Рекомендации
|
## Рекомендации
|
||||||
|
|
||||||
- **Для повседневной работы:** `high` или `xhigh` — работает одинаково хорошо у всех провайдеров
|
- **Для повседневной работы:** `high` или `xhigh` — работает одинаково хорошо у всех провайдеров
|
||||||
- **`max` effort:** имеет реальный эффект только у **Anthropic** и **DeepSeek**. Для GPT маппится в `xhigh`, для Gemini и Kimi — в их максимальный уровень
|
- **`max` effort:** имеет реальный эффект только у **Anthropic** и **DeepSeek**. Для GPT маппится в `xhigh`, для Gemini и Kimi — в их максимальный уровень
|
||||||
- **`low`/`medium`:** у DeepSeek и Kimi фактически не снижают reasoning — DeepSeek поднимет до `high`, Kimi просто включит thinking
|
- **`low`/`medium`:** у DeepSeek и Kimi фактически не снижают reasoning — DeepSeek поднимет до `high`, Kimi просто включит thinking
|
||||||
|
- **Смена уровня:** на `low..xhigh` обычным `/effort`; из `max` — через `AI_EFFORT=<lvl> ai-<launcher>` (в max-сессии `/effort` залочен env-переменной, см. «Persistence effort»)
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
# Сохраняет текущий effortLevel в кэш лаунчера при завершении сессии.
|
|
||||||
# /effort внутри Claude Code обновляет settings.json - мы читаем оттуда.
|
|
||||||
launcher="${AI_LAUNCHER:-}"
|
|
||||||
[ -z "$launcher" ] && exit 0
|
|
||||||
cat /dev/stdin > /dev/null 2>&1 # drain stdin (Claude Code передаёт JSON)
|
|
||||||
mkdir -p "$HOME/.cache/ai-setup"
|
|
||||||
python3 - "$HOME/.claude/settings.json" "$HOME/.cache/ai-setup" "$launcher" <<'PYEOF'
|
|
||||||
import json, os, sys
|
|
||||||
settings_path, cache_dir, launcher = sys.argv[1], sys.argv[2], sys.argv[3]
|
|
||||||
if not os.path.exists(settings_path):
|
|
||||||
sys.exit(0)
|
|
||||||
try:
|
|
||||||
d = json.load(open(settings_path))
|
|
||||||
except Exception:
|
|
||||||
sys.exit(0)
|
|
||||||
effort = d.get('effortLevel', '')
|
|
||||||
if effort:
|
|
||||||
open(os.path.join(cache_dir, f'effort_{launcher}'), 'w').write(effort)
|
|
||||||
model = d.get('model', '')
|
|
||||||
if model:
|
|
||||||
open(os.path.join(cache_dir, f'model_{launcher}'), 'w').write(model)
|
|
||||||
PYEOF
|
|
||||||
exit 0
|
|
||||||
@@ -42,11 +42,12 @@ printf "\033[38;5;252m%s\033[00m" "$short_cwd"
|
|||||||
if [ -n "$model" ]; then
|
if [ -n "$model" ]; then
|
||||||
brand_color=$(_brand_color "${AI_LAUNCHER:-}")
|
brand_color=$(_brand_color "${AI_LAUNCHER:-}")
|
||||||
effort=$(echo "$input" | jq -r ".effort.level // empty")
|
effort=$(echo "$input" | jq -r ".effort.level // empty")
|
||||||
# Сохраняем effort для persistence между сессиями одного лаунчера
|
# Ловим выбранный уровень в кэш лаунчера (чтобы запомнить max между сессиями).
|
||||||
if [ -n "${AI_LAUNCHER:-}" ] && [ -n "$effort" ]; then
|
# Когда CLAUDE_CODE_EFFORT_LEVEL выставлена (восстановленная max-сессия) - уровень
|
||||||
|
# форсится env, кэш НЕ трогаем, чтобы дисплей-баг (.effort.level=xhigh) не затёр max.
|
||||||
|
if [ -n "${AI_LAUNCHER:-}" ] && [ -z "${CLAUDE_CODE_EFFORT_LEVEL:-}" ] && [ -n "$effort" ]; then
|
||||||
effort_file="$HOME/.cache/ai-setup/effort_${AI_LAUNCHER}"
|
effort_file="$HOME/.cache/ai-setup/effort_${AI_LAUNCHER}"
|
||||||
prev_effort=$(cat "$effort_file" 2>/dev/null)
|
if [ "$effort" != "$(cat "$effort_file" 2>/dev/null)" ]; then
|
||||||
if [ "$effort" != "$prev_effort" ]; then
|
|
||||||
mkdir -p "$HOME/.cache/ai-setup"
|
mkdir -p "$HOME/.cache/ai-setup"
|
||||||
echo "$effort" > "$effort_file"
|
echo "$effort" > "$effort_file"
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -683,39 +683,39 @@ else
|
|||||||
warn "Файл $STATUSLINE_SRC не найден, пропускаю"
|
warn "Файл $STATUSLINE_SRC не найден, пропускаю"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# ── 6.7.0. Хук effort-save (сохраняет effort при завершении сессии) ──
|
# ── 6.7.0. Чистка устаревшего хука effort-save ──────────────
|
||||||
info "Деплою хук effort-save..."
|
# effort/model теперь персистятся нативно в settings.json каждого CLAUDE_CONFIG_DIR
|
||||||
EFFORT_HOOK_SRC="$SCRIPT_DIR/home-configs/claude/hooks/effort-save-hook.sh"
|
# (полная изоляция лаунчеров), самопальный кэш ~/.cache/ai-setup/{effort,model}_* не нужен.
|
||||||
EFFORT_HOOK_DST="$HOME/.claude/hooks/effort-save-hook.sh"
|
# Удаляем старый хук с диска и из ~/.claude/settings.json (нотифаер в Stop сохраняем).
|
||||||
mkdir -p "$HOME/.claude/hooks"
|
info "Удаляю устаревший хук effort-save..."
|
||||||
if [ -f "$EFFORT_HOOK_SRC" ]; then
|
rm -f "$HOME/.claude/hooks/effort-save-hook.sh"
|
||||||
cp "$EFFORT_HOOK_SRC" "$EFFORT_HOOK_DST"
|
# Осиротевший кэш моделей (источник старой протечки между ai-*); effort_* НЕ трогаем -
|
||||||
chmod +x "$EFFORT_HOOK_DST"
|
# он снова используется для персиста effort (включая max) через CLAUDE_CODE_EFFORT_LEVEL.
|
||||||
python3 - "$HOME/.claude/settings.json" "$EFFORT_HOOK_DST" <<'PYEOF'
|
rm -f "$HOME"/.cache/ai-setup/model_*
|
||||||
|
python3 - "$HOME/.claude/settings.json" <<'PYEOF'
|
||||||
import sys, json, os
|
import sys, json, os
|
||||||
settings_path, hook_path = sys.argv[1], sys.argv[2]
|
settings_path = sys.argv[1]
|
||||||
data = {}
|
if not os.path.exists(settings_path):
|
||||||
if os.path.exists(settings_path):
|
sys.exit(0)
|
||||||
|
try:
|
||||||
with open(settings_path) as f:
|
with open(settings_path) as f:
|
||||||
try: data = json.load(f)
|
data = json.load(f)
|
||||||
except json.JSONDecodeError: pass
|
except Exception:
|
||||||
data.setdefault("hooks", {}).setdefault("Stop", [{"hooks": []}])
|
sys.exit(0)
|
||||||
hook_cmd = f'bash "{hook_path}"'
|
stop = data.get("hooks", {}).get("Stop")
|
||||||
stop_hooks = data["hooks"]["Stop"]
|
if isinstance(stop, list):
|
||||||
already = any(
|
for entry in stop:
|
||||||
any(h.get("command", "") == hook_cmd for h in entry.get("hooks", []))
|
hooks = entry.get("hooks")
|
||||||
for entry in stop_hooks
|
if isinstance(hooks, list):
|
||||||
)
|
entry["hooks"] = [h for h in hooks if "effort-save-hook" not in h.get("command", "")]
|
||||||
if not already:
|
data["hooks"]["Stop"] = [e for e in stop if e.get("hooks")]
|
||||||
stop_hooks[0]["hooks"].append({"type": "command", "command": hook_cmd})
|
if not data["hooks"]["Stop"]:
|
||||||
with open(settings_path, "w") as f:
|
del data["hooks"]["Stop"]
|
||||||
|
with open(settings_path, "w") as f:
|
||||||
json.dump(data, f, indent=2, ensure_ascii=False)
|
json.dump(data, f, indent=2, ensure_ascii=False)
|
||||||
f.write("\n")
|
f.write("\n")
|
||||||
PYEOF
|
PYEOF
|
||||||
success "Хук effort-save установлен"
|
success "Старый хук effort-save удалён"
|
||||||
else
|
|
||||||
warn "Файл $EFFORT_HOOK_SRC не найден, пропускаю"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ── 6.7.1. Хук switch-account ───────────────────────────────────
|
# ── 6.7.1. Хук switch-account ───────────────────────────────────
|
||||||
info "Деплою хук switch-account..."
|
info "Деплою хук switch-account..."
|
||||||
@@ -1077,71 +1077,95 @@ _open_browser() {
|
|||||||
else echo "Откройте вручную: $url"; fi
|
else echo "Откройте вручную: $url"; fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# _restore_effort: читает сохранённый effort для текущего AI_LAUNCHER из кэша
|
# _setup_isolated_config: готовит изолированную папку CLAUDE_CONFIG_DIR для лаунчера.
|
||||||
# и записывает его в settings.json, чтобы Claude Code подхватил нужный уровень.
|
# Каждый сторонний провайдер получает собственные settings.json и .claude.json,
|
||||||
# Не передаём --effort через CLI, чтобы /effort внутри сессии работал без блокировки.
|
# поэтому выбор модели и кэш кастом-моделей НЕ протекают между ai-* лаунчерами.
|
||||||
_restore_effort() {
|
# Общие ресурсы (skills, CLAUDE.md) шарятся симлинком из ~/.claude.
|
||||||
local default_effort="${1:-high}"
|
# model и effortLevel сидируются как дефолты - выбор юзера через /model и /effort
|
||||||
local launcher="${AI_LAUNCHER:-}"
|
# (для low/medium/high/xhigh) сохраняется нативно в этом же settings.json.
|
||||||
[ -z "$launcher" ] && return
|
# Уровень max обрабатывается отдельно в _apply_effort (settings.json его не хранит).
|
||||||
local effort_file="$HOME/.cache/ai-setup/effort_${launcher}"
|
# Использование: _setup_isolated_config <launcher> <default_model> <default_effort> <available_models_json>
|
||||||
local effort
|
_setup_isolated_config() {
|
||||||
effort=$(cat "$effort_file" 2>/dev/null)
|
local launcher="$1" default_model="$2" default_effort="${3:-high}" avail="${4:-}"
|
||||||
[ -z "$effort" ] && effort="$default_effort"
|
local cfg="$HOME/.config/ai-setup/cfg/$launcher"
|
||||||
|
mkdir -p "$cfg"
|
||||||
|
# Общие ресурсы из ~/.claude (единый источник правды)
|
||||||
|
ln -sfn "$HOME/.claude/skills" "$cfg/skills"
|
||||||
|
ln -sfn "$HOME/.claude/CLAUDE.md" "$cfg/CLAUDE.md"
|
||||||
|
[ -e "$HOME/.claude/agents" ] && ln -sfn "$HOME/.claude/agents" "$cfg/agents"
|
||||||
|
# .claude.json в свежей папке: пропускаем онбординг
|
||||||
|
[ -f "$cfg/.claude.json" ] || echo '{"hasCompletedOnboarding": true}' > "$cfg/.claude.json"
|
||||||
|
python3 - "$cfg/settings.json" "$HOME/.claude/statusline-command.sh" \
|
||||||
|
"$default_model" "$default_effort" "$avail" <<'PYEOF'
|
||||||
|
import sys, json, os
|
||||||
|
cfg_settings, statusline, model, effort, avail = sys.argv[1:6]
|
||||||
|
data = {}
|
||||||
|
if os.path.exists(cfg_settings):
|
||||||
|
try:
|
||||||
|
with open(cfg_settings) as f:
|
||||||
|
data = json.load(f)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
# Структурные настройки лаунчера (переустанавливаем всегда)
|
||||||
|
data["statusLine"] = {"type": "command", "command": f"bash {statusline}"}
|
||||||
|
data["skipDangerousModePermissionPrompt"] = True
|
||||||
|
data.setdefault("hooks", {})["SessionStart"] = [{"hooks": [{"type": "command", "command": "true"}]}]
|
||||||
|
# availableModels - белый список пикера (политика лаунчера)
|
||||||
|
if avail:
|
||||||
|
data["availableModels"] = json.loads(avail)
|
||||||
|
else:
|
||||||
|
data.pop("availableModels", None)
|
||||||
|
# model/effortLevel - сидируем дефолты, не перетирая выбор юзера (нативный persistence)
|
||||||
|
if model:
|
||||||
|
data.setdefault("model", model)
|
||||||
|
data.setdefault("effortLevel", effort)
|
||||||
|
with open(cfg_settings, "w") as f:
|
||||||
|
json.dump(data, f, indent=2, ensure_ascii=False)
|
||||||
|
f.write("\n")
|
||||||
|
PYEOF
|
||||||
|
}
|
||||||
|
|
||||||
|
# _apply_effort: per-launcher persistence уровня effort (гибрид).
|
||||||
|
# - low/medium/high/xhigh живут нативно в settings.json лаунчера -> /effort работает,
|
||||||
|
# уровень сохраняется между сессиями, env-переменная НЕ ставится.
|
||||||
|
# - max единственный нельзя сохранить в settings.json (он session-only), поэтому
|
||||||
|
# его восстанавливаем через CLAUDE_CODE_EFFORT_LEVEL. В такой max-сессии /effort
|
||||||
|
# залочен env-переменной (ограничение Claude Code).
|
||||||
|
# Текущий уровень (вкл. max) ловит статусбар в ~/.cache/ai-setup/effort_<launcher>.
|
||||||
|
# Сменить уровень из max: AI_EFFORT=<lvl> ai-<launcher>.
|
||||||
|
# Использование: _apply_effort <launcher> <default_effort>
|
||||||
|
_apply_effort() {
|
||||||
|
local launcher="$1" default_effort="${2:-high}"
|
||||||
|
local f="$HOME/.cache/ai-setup/effort_${launcher}"
|
||||||
|
local settings="${CLAUDE_CONFIG_DIR:-$HOME/.claude}/settings.json"
|
||||||
|
local eff
|
||||||
|
if [ -n "${AI_EFFORT:-}" ]; then
|
||||||
|
# Явный override: запоминаем и применяем
|
||||||
|
eff="$AI_EFFORT"
|
||||||
mkdir -p "$HOME/.cache/ai-setup"
|
mkdir -p "$HOME/.cache/ai-setup"
|
||||||
python3 - "$HOME/.claude/settings.json" "$effort" <<'PYEOF'
|
echo "$eff" > "$f"
|
||||||
|
else
|
||||||
|
eff=$(cat "$f" 2>/dev/null)
|
||||||
|
fi
|
||||||
|
if [ "$eff" = "max" ]; then
|
||||||
|
# Единственный способ восстановить max между сессиями
|
||||||
|
export CLAUDE_CODE_EFFORT_LEVEL=max
|
||||||
|
elif [ -n "${AI_EFFORT:-}" ] && [ -n "$eff" ]; then
|
||||||
|
# Явный сброс на low/medium/high/xhigh - пишем нативно в settings.json лаунчера
|
||||||
|
python3 - "$settings" "$eff" <<'PYEOF'
|
||||||
import sys, json, os
|
import sys, json, os
|
||||||
settings_path, effort = sys.argv[1], sys.argv[2]
|
p, eff = sys.argv[1], sys.argv[2]
|
||||||
data = {}
|
d = {}
|
||||||
if os.path.exists(settings_path):
|
if os.path.exists(p):
|
||||||
try:
|
try: d = json.load(open(p))
|
||||||
with open(settings_path) as f:
|
except Exception: pass
|
||||||
data = json.load(f)
|
d["effortLevel"] = eff
|
||||||
except Exception:
|
os.makedirs(os.path.dirname(p), exist_ok=True)
|
||||||
pass
|
with open(p, "w") as fp:
|
||||||
data['effortLevel'] = effort
|
json.dump(d, fp, indent=2, ensure_ascii=False); fp.write("\n")
|
||||||
with open(settings_path, 'w') as f:
|
|
||||||
json.dump(data, f, indent=2, ensure_ascii=False)
|
|
||||||
f.write('\n')
|
|
||||||
PYEOF
|
PYEOF
|
||||||
}
|
fi
|
||||||
|
# Иначе (≤xhigh без AI_EFFORT): ничего не делаем - effortLevel уже персистнут нативно.
|
||||||
_restore_model() {
|
|
||||||
local default_model="${1:-}"
|
|
||||||
local launcher="${AI_LAUNCHER:-}"
|
|
||||||
[ -z "$launcher" ] && return
|
|
||||||
local model_file="$HOME/.cache/ai-setup/model_${launcher}"
|
|
||||||
local model
|
|
||||||
model=$(cat "$model_file" 2>/dev/null)
|
|
||||||
[ -z "$model" ] && model="$default_model"
|
|
||||||
[ -z "$model" ] && return
|
|
||||||
python3 - "$HOME/.claude/settings.json" "$model" <<'PYEOF'
|
|
||||||
import sys, json, os
|
|
||||||
settings_path, model = sys.argv[1], sys.argv[2]
|
|
||||||
data = {}
|
|
||||||
if os.path.exists(settings_path):
|
|
||||||
try:
|
|
||||||
with open(settings_path) as f:
|
|
||||||
data = json.load(f)
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
data['model'] = model
|
|
||||||
with open(settings_path, 'w') as f:
|
|
||||||
json.dump(data, f, indent=2, ensure_ascii=False)
|
|
||||||
f.write('\n')
|
|
||||||
PYEOF
|
|
||||||
}
|
|
||||||
|
|
||||||
# _restore_model_str: возвращает сохранённую модель строкой (для ANTHROPIC_MODEL env var)
|
|
||||||
_restore_model_str() {
|
|
||||||
local default_model="${1:-}"
|
|
||||||
local launcher="${AI_LAUNCHER:-}"
|
|
||||||
[ -z "$launcher" ] && echo "$default_model" && return
|
|
||||||
local model_file="$HOME/.cache/ai-setup/model_${launcher}"
|
|
||||||
local model
|
|
||||||
model=$(cat "$model_file" 2>/dev/null)
|
|
||||||
[ -z "$model" ] && model="$default_model"
|
|
||||||
echo "$model"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_build_ai_sys_prompt() {
|
_build_ai_sys_prompt() {
|
||||||
@@ -1266,13 +1290,19 @@ _PROMPT_FILE=$(mktemp /tmp/ai-sys-prompt.XXXXXX)
|
|||||||
trap 'rm -f "$_PROMPT_FILE"' EXIT INT TERM
|
trap 'rm -f "$_PROMPT_FILE"' EXIT INT TERM
|
||||||
_build_ai_sys_prompt > "$_PROMPT_FILE"
|
_build_ai_sys_prompt > "$_PROMPT_FILE"
|
||||||
export AI_LAUNCHER=deepseek
|
export AI_LAUNCHER=deepseek
|
||||||
_restore_effort high
|
export CLAUDE_CONFIG_DIR="$HOME/.config/ai-setup/cfg/deepseek"
|
||||||
|
# Пикер: только DeepSeek V4 Pro (opus) и DeepSeek V4 Flash (haiku), дефолт - Pro
|
||||||
|
_setup_isolated_config deepseek opus high '["opus", "haiku"]'
|
||||||
|
_apply_effort deepseek high
|
||||||
ANTHROPIC_BASE_URL=https://api.deepseek.com/anthropic \
|
ANTHROPIC_BASE_URL=https://api.deepseek.com/anthropic \
|
||||||
ANTHROPIC_AUTH_TOKEN="$api_key" \
|
ANTHROPIC_AUTH_TOKEN="$api_key" \
|
||||||
ANTHROPIC_MODEL=deepseek-v4-pro \
|
|
||||||
ANTHROPIC_DEFAULT_OPUS_MODEL=deepseek-v4-pro \
|
ANTHROPIC_DEFAULT_OPUS_MODEL=deepseek-v4-pro \
|
||||||
|
ANTHROPIC_DEFAULT_OPUS_MODEL_NAME="DeepSeek V4 Pro" \
|
||||||
|
ANTHROPIC_DEFAULT_OPUS_MODEL_DESCRIPTION="DeepSeek V4 Pro - флагман для сложных задач" \
|
||||||
ANTHROPIC_DEFAULT_SONNET_MODEL=deepseek-v4-pro \
|
ANTHROPIC_DEFAULT_SONNET_MODEL=deepseek-v4-pro \
|
||||||
ANTHROPIC_DEFAULT_HAIKU_MODEL=deepseek-v4-flash \
|
ANTHROPIC_DEFAULT_HAIKU_MODEL=deepseek-v4-flash \
|
||||||
|
ANTHROPIC_DEFAULT_HAIKU_MODEL_NAME="DeepSeek V4 Flash" \
|
||||||
|
ANTHROPIC_DEFAULT_HAIKU_MODEL_DESCRIPTION="DeepSeek V4 Flash - быстрый и дешёвый" \
|
||||||
CLAUDE_CODE_SUBAGENT_MODEL=deepseek-v4-flash \
|
CLAUDE_CODE_SUBAGENT_MODEL=deepseek-v4-flash \
|
||||||
CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1 \
|
CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1 \
|
||||||
claude --dangerously-skip-permissions --system-prompt-file "$_PROMPT_FILE" "$@"
|
claude --dangerously-skip-permissions --system-prompt-file "$_PROMPT_FILE" "$@"
|
||||||
@@ -1340,11 +1370,15 @@ _PROMPT_FILE=$(mktemp /tmp/ai-sys-prompt.XXXXXX)
|
|||||||
trap 'rm -f "$_PROMPT_FILE"' EXIT INT TERM
|
trap 'rm -f "$_PROMPT_FILE"' EXIT INT TERM
|
||||||
_build_ai_sys_prompt > "$_PROMPT_FILE"
|
_build_ai_sys_prompt > "$_PROMPT_FILE"
|
||||||
export AI_LAUNCHER=kimi
|
export AI_LAUNCHER=kimi
|
||||||
_restore_effort high
|
export CLAUDE_CONFIG_DIR="$HOME/.config/ai-setup/cfg/kimi"
|
||||||
|
# Пикер: единственная модель Kimi K2.6 (под алиасом opus)
|
||||||
|
_setup_isolated_config kimi opus high '["opus"]'
|
||||||
|
_apply_effort kimi high
|
||||||
ANTHROPIC_BASE_URL=https://api.kimi.com/coding \
|
ANTHROPIC_BASE_URL=https://api.kimi.com/coding \
|
||||||
ANTHROPIC_AUTH_TOKEN="$api_key" \
|
ANTHROPIC_AUTH_TOKEN="$api_key" \
|
||||||
ANTHROPIC_MODEL=kimi-k2.6 \
|
|
||||||
ANTHROPIC_DEFAULT_OPUS_MODEL=kimi-k2.6 \
|
ANTHROPIC_DEFAULT_OPUS_MODEL=kimi-k2.6 \
|
||||||
|
ANTHROPIC_DEFAULT_OPUS_MODEL_NAME="Kimi K2.6" \
|
||||||
|
ANTHROPIC_DEFAULT_OPUS_MODEL_DESCRIPTION="Kimi K2.6 (Moonshot AI)" \
|
||||||
ANTHROPIC_DEFAULT_SONNET_MODEL=kimi-k2.6 \
|
ANTHROPIC_DEFAULT_SONNET_MODEL=kimi-k2.6 \
|
||||||
ANTHROPIC_DEFAULT_HAIKU_MODEL=kimi-k2.6 \
|
ANTHROPIC_DEFAULT_HAIKU_MODEL=kimi-k2.6 \
|
||||||
CLAUDE_CODE_SUBAGENT_MODEL=kimi-k2.6 \
|
CLAUDE_CODE_SUBAGENT_MODEL=kimi-k2.6 \
|
||||||
@@ -1414,11 +1448,16 @@ _PROMPT_FILE=$(mktemp /tmp/ai-sys-prompt.XXXXXX)
|
|||||||
trap 'rm -f "$_PROMPT_FILE"' EXIT INT TERM
|
trap 'rm -f "$_PROMPT_FILE"' EXIT INT TERM
|
||||||
_build_ai_sys_prompt > "$_PROMPT_FILE"
|
_build_ai_sys_prompt > "$_PROMPT_FILE"
|
||||||
export AI_LAUNCHER=openrouter
|
export AI_LAUNCHER=openrouter
|
||||||
_restore_effort high
|
export CLAUDE_CONFIG_DIR="$HOME/.config/ai-setup/cfg/openrouter"
|
||||||
_MODEL=$(_restore_model_str "openai/gpt-5.5")
|
# openrouter - гибкий лаунчер: пикер не ограничиваем (availableModels пустой),
|
||||||
|
# gpt-5.5 добавляем отдельным пунктом и делаем дефолтом
|
||||||
|
export ANTHROPIC_CUSTOM_MODEL_OPTION="openai/gpt-5.5"
|
||||||
|
export ANTHROPIC_CUSTOM_MODEL_OPTION_NAME="GPT-5.5"
|
||||||
|
export ANTHROPIC_CUSTOM_MODEL_OPTION_DESCRIPTION="OpenRouter: openai/gpt-5.5"
|
||||||
|
_setup_isolated_config openrouter "openai/gpt-5.5" high ''
|
||||||
|
_apply_effort openrouter high
|
||||||
ANTHROPIC_BASE_URL=https://openrouter.ai/api \
|
ANTHROPIC_BASE_URL=https://openrouter.ai/api \
|
||||||
ANTHROPIC_AUTH_TOKEN="$api_key" \
|
ANTHROPIC_AUTH_TOKEN="$api_key" \
|
||||||
ANTHROPIC_MODEL=$_MODEL \
|
|
||||||
ANTHROPIC_DEFAULT_OPUS_MODEL=anthropic/claude-4.8-opus \
|
ANTHROPIC_DEFAULT_OPUS_MODEL=anthropic/claude-4.8-opus \
|
||||||
ANTHROPIC_DEFAULT_SONNET_MODEL=anthropic/claude-4.6-sonnet \
|
ANTHROPIC_DEFAULT_SONNET_MODEL=anthropic/claude-4.6-sonnet \
|
||||||
ANTHROPIC_DEFAULT_HAIKU_MODEL=openai/gpt-5.5 \
|
ANTHROPIC_DEFAULT_HAIKU_MODEL=openai/gpt-5.5 \
|
||||||
@@ -1469,8 +1508,11 @@ _PROMPT_FILE=$(mktemp /tmp/ai-sys-prompt.XXXXXX)
|
|||||||
trap 'rm -f "$_PROMPT_FILE"' EXIT INT TERM
|
trap 'rm -f "$_PROMPT_FILE"' EXIT INT TERM
|
||||||
_build_ai_sys_prompt > "$_PROMPT_FILE"
|
_build_ai_sys_prompt > "$_PROMPT_FILE"
|
||||||
export AI_LAUNCHER=claude
|
export AI_LAUNCHER=claude
|
||||||
_restore_effort xhigh
|
# ai-claude работает в дефолтном ~/.claude (нативный логин и аккаунты).
|
||||||
_restore_model "sonnet"
|
# Модель хранится нативно в ~/.claude/settings.json; другие ai-* лаунчеры теперь
|
||||||
|
# изолированы в своих CLAUDE_CONFIG_DIR, поэтому в пикер не протекают чужие модели -
|
||||||
|
# показываются только нативные модели Claude Code.
|
||||||
|
_apply_effort claude xhigh
|
||||||
claude --dangerously-skip-permissions --system-prompt-file "$_PROMPT_FILE" "$@"
|
claude --dangerously-skip-permissions --system-prompt-file "$_PROMPT_FILE" "$@"
|
||||||
CLAUDEEOF
|
CLAUDEEOF
|
||||||
chmod +x "$BIN_DIR/ai-claude"
|
chmod +x "$BIN_DIR/ai-claude"
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ test_kimi_claude_launcher() {
|
|||||||
# ── ai-kimi: uses official Kimi API ──────────────────────────────────────
|
# ── ai-kimi: uses official Kimi API ──────────────────────────────────────
|
||||||
test_kimi_official_api() {
|
test_kimi_official_api() {
|
||||||
if echo "$KIMI_SECTION" | grep -q 'api.kimi.com/coding' \
|
if echo "$KIMI_SECTION" | grep -q 'api.kimi.com/coding' \
|
||||||
&& echo "$KIMI_SECTION" | grep -q 'ANTHROPIC_MODEL=kimi-k2.6' \
|
&& echo "$KIMI_SECTION" | grep -q 'ANTHROPIC_DEFAULT_OPUS_MODEL=kimi-k2.6' \
|
||||||
&& ! echo "$KIMI_SECTION" | grep -q 'artemox'; then
|
&& ! echo "$KIMI_SECTION" | grep -q 'artemox'; then
|
||||||
ok "ai-kimi: uses official Kimi API and model"
|
ok "ai-kimi: uses official Kimi API and model"
|
||||||
else
|
else
|
||||||
|
|||||||
Reference in New Issue
Block a user