#!/bin/bash # hf-launch — Launch coding agents with HF Inference Providers # # Dependencies: curl, jq, fzf, HF_TOKEN # # Usage: # hf tool run launch # interactive picker # hf tool run launch claude # interactive model picker # hf tool run launch claude --model Qwen/Qwen3-235B-A22B # explicit model set -e # ── Token ──────────────────────────────────────────────────────────────────── HF_TOKEN="${HF_TOKEN:-}" if [[ -z "$HF_TOKEN" ]]; then HF_TOKEN=$(python3 -c "from huggingface_hub.utils import get_token; print(get_token() or '', end='')" 2>/dev/null) fi if [[ -z "$HF_TOKEN" ]]; then echo "Error: Not logged in. Run 'hf auth login' or export HF_TOKEN." >&2 exit 1 fi # ── Usage ──────────────────────────────────────────────────────────────────── usage() { cat >&2 << 'EOF' Usage: hf tool run launch [agent] [options] [-- extra-args...] Agents: claude, opencode Options: --model Model ID (e.g. Qwen/Qwen3-235B-A22B) --provider Inference provider (e.g. fireworks-ai). Default: auto -h, --help Show this help Examples: hf tool run launch hf tool run launch claude hf tool run launch claude --model Qwen/Qwen3-235B-A22B hf tool run launch claude --model Qwen/Qwen3-235B-A22B --provider fireworks-ai hf tool run launch opencode EOF exit 1 } # ── Parse args ─────────────────────────────────────────────────────────────── AGENT="" MODEL="" PROVIDER="" EXTRA_ARGS=() case "${1:-}" in -h|--help) usage ;; --) shift; EXTRA_ARGS=("$@") ;; "") ;; -*) ;; # flags handled below *) AGENT="$1"; shift ;; esac while [[ $# -gt 0 ]]; do case "$1" in --model) MODEL="$2"; shift 2 ;; --provider) PROVIDER="$2"; shift 2 ;; -h|--help) usage ;; --) shift; EXTRA_ARGS=("$@"); break ;; *) EXTRA_ARGS+=("$1"); shift ;; esac done # ── Fetch models & pick ───────────────────────────────────────────────────── if [[ -z "$MODEL" ]]; then MODEL_DATA=$(curl -s "https://router.huggingface.co/v1/models" \ -H "Authorization: Bearer $HF_TOKEN" 2>/dev/null) MODEL=$(echo "$MODEL_DATA" | jq -r '.data[].id' | fzf --prompt="HF Model: " \ --height=50% \ --reverse \ --header="HuggingFace Router - Select Model" \ --preview='echo {}' \ --preview-window=up:1) if [[ -z "$MODEL" ]]; then echo "No model selected" >&2 exit 1 fi PROVIDER=$( (echo "auto"; echo "$MODEL_DATA" | jq -r --arg model "$MODEL" \ '.data[] | select(.id == $model) | .providers[].provider') \ | fzf --prompt="Provider: " \ --height=20% \ --reverse \ --header="Select Provider for $MODEL (auto = no suffix)") if [[ -z "$PROVIDER" ]]; then echo "No provider selected" >&2 exit 1 fi fi # ── Select agent (if not provided) ─────────────────────────────────────────── if [[ -z "$AGENT" ]]; then AGENT=$(printf "claude\nopencode" | fzf --prompt="CLI: " \ --height=10% \ --reverse \ --header="Select CLI") if [[ -z "$AGENT" ]]; then echo "No CLI selected" >&2 exit 1 fi fi case "$AGENT" in claude|opencode) ;; *) echo "Error: Unknown agent '$AGENT'. Choose: claude, opencode" >&2; exit 1 ;; esac # ── Build model string ─────────────────────────────────────────────────────── if [[ "$PROVIDER" == "auto" || -z "$PROVIDER" ]]; then MODEL_STRING="$MODEL" else MODEL_STRING="${MODEL}:${PROVIDER}" fi echo "→ $AGENT @ $MODEL_STRING" >&2 # ── Launch ─────────────────────────────────────────────────────────────────── case "$AGENT" in claude) export ANTHROPIC_API_KEY="$HF_TOKEN" export ANTHROPIC_AUTH_TOKEN="$HF_TOKEN" export ANTHROPIC_BASE_URL="https://router.huggingface.co" export ANTHROPIC_DEFAULT_SONNET_MODEL="$MODEL_STRING" export ANTHROPIC_DEFAULT_HAIKU_MODEL="$MODEL_STRING" export ANTHROPIC_DEFAULT_OPUS_MODEL="$MODEL_STRING" exec claude --model "$MODEL_STRING" "${EXTRA_ARGS[@]}" ;; opencode) exec opencode -m "huggingface/$MODEL_STRING" "${EXTRA_ARGS[@]}" ;; esac