Created
June 27, 2026 00:31
-
-
Save johnandersen777/4c2243ea1ae6e3d03d8abeadd36d98cf to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| # Claude Code -> Charm Hyper (GLM-5.2) via a local litellm proxy. | |
| # | |
| # Hyper's Anthropic /v1/messages endpoint rejects `{"role":"system"}` inside | |
| # the messages array (400 unsupported message role: system), which Claude Code | |
| # emits. Hyper's OpenAI /v1/chat/completions endpoint accepts it. litellm | |
| # translates Anthropic Messages -> OpenAI Chat Completions, moving system into | |
| # the OpenAI messages array. So we run litellm locally on an ephemeral port, | |
| # point the Claude CLI at it, and tear it down when claude exits. | |
| set -euo pipefail | |
| HYPER_API_KEY="sk-hyper-..." | |
| HYPER_API_BASE="https://hyper.charm.land/v1" | |
| LITELLM_MASTER_KEY="sk-litellm-local" | |
| CONFIG="$(mktemp -t glm-hyper-claude-litellm.XXXXXX.yaml)" | |
| trap 'rm -f "$CONFIG"' EXIT | |
| cat > "$CONFIG" <<EOF | |
| general_settings: | |
| master_key: "${LITELLM_MASTER_KEY}" | |
| model_list: | |
| - model_name: "glm-5.2" | |
| litellm_params: | |
| model: "openai/glm-5.2" | |
| api_base: "${HYPER_API_BASE}" | |
| api_key: "${HYPER_API_KEY}" | |
| input_cost_per_token: 0.0 | |
| output_cost_per_token: 0.0 | |
| - model_name: "deepseek-v4-flash" | |
| litellm_params: | |
| model: "openai/deepseek-v4-flash" | |
| api_base: "${HYPER_API_BASE}" | |
| api_key: "${HYPER_API_KEY}" | |
| input_cost_per_token: 0.0 | |
| output_cost_per_token: 0.0 | |
| EOF | |
| # Single OS bind for an ephemeral port (no listen-close-rebind race). | |
| PORT="$(python3 -c 'import socket; s=socket.socket(); s.bind(("127.0.0.1",0)); print(s.getsockname()[1]); s.close()')" | |
| LOG="$(mktemp -t glm-hyper-claude-litellm.XXXXXX.log)" | |
| LITELLM_PID="" | |
| cleanup() { | |
| if [[ -n "${LITELLM_PID:-}" ]] && kill -0 "${LITELLM_PID}" 2>/dev/null; then | |
| kill "${LITELLM_PID}" 2>/dev/null || true | |
| wait "${LITELLM_PID}" 2>/dev/null || true | |
| fi | |
| rm -f "$LOG" | |
| } | |
| trap cleanup EXIT INT TERM | |
| PYTHONUTF8=1 uv tool run --python 3.13 --with 'litellm[proxy]' litellm \ | |
| --config "$CONFIG" --port "$PORT" >"$LOG" 2>&1 & | |
| LITELLM_PID=$! | |
| HEALTHY=0 | |
| for _ in $(seq 1 120); do | |
| # Bail early if litellm already exited | |
| if ! kill -0 "${LITELLM_PID}" 2>/dev/null; then | |
| echo "glm-hyper-claude: litellm process (PID ${LITELLM_PID}) exited prematurely. Log:" >&2 | |
| cat "$LOG" >&2 | |
| exit 1 | |
| fi | |
| if curl -fsS -o /dev/null "http://127.0.0.1:${PORT}/health/liveness" 2>/dev/null; then | |
| HEALTHY=1 | |
| break | |
| fi | |
| sleep 0.5 | |
| done | |
| if [[ "${HEALTHY}" -eq 0 ]]; then | |
| echo "glm-hyper-claude: litellm proxy failed to become healthy after 60s. Log:" >&2 | |
| cat "$LOG" >&2 | |
| exit 1 | |
| fi | |
| export ANTHROPIC_MODEL="glm-5.2" | |
| export ANTHROPIC_DEFAULT_OPUS_MODEL="glm-5.2" | |
| export ANTHROPIC_DEFAULT_SONNET_MODEL="glm-5.2" | |
| export ANTHROPIC_DEFAULT_HAIKU_MODEL="deepseek-v4-flash" | |
| export CLAUDE_CODE_SUBAGENT_MODEL="glm-5.2" | |
| export CLAUDE_CODE_EFFORT_LEVEL="high" | |
| export ANTHROPIC_BASE_URL="http://127.0.0.1:${PORT}" | |
| export ANTHROPIC_API_KEY="${LITELLM_MASTER_KEY}" | |
| claude --allow-dangerously-skip-permissions --dangerously-skip-permissions "$@" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment