claude.fish

  1# SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
  2#
  3# SPDX-License-Identifier: Unlicense
  4
  5# Claude Code agent definition for synu
  6# Provides model configuration for routing through Synthetic API
  7
  8# Source cache functions
  9source (status dirname)/../_synu_cache.fish
 10
 11# Fallback defaults (used when no cache entry exists)
 12set -g _synu_claude_fallback_opus "hf:moonshotai/Kimi-K2-Thinking"
 13set -g _synu_claude_fallback_sonnet "hf:zai-org/GLM-4.6"
 14set -g _synu_claude_fallback_haiku "hf:deepseek-ai/DeepSeek-V3.1-Terminus"
 15set -g _synu_claude_fallback_agent "hf:zai-org/GLM-4.6"
 16
 17function _synu_claude_default --description "Get default model: _synu_claude_default slot"
 18    set -l slot $argv[1]
 19    set -l cached (_synu_cache_get claude $slot)
 20    if test $status -eq 0
 21        echo $cached
 22    else
 23        set -l var_name _synu_claude_fallback_$slot
 24        echo $$var_name
 25    end
 26end
 27
 28function _synu_agent_claude_flags --description "Return argparse-compatible flag specification"
 29    echo "H/heavy="
 30    echo "M/medium="
 31    echo "l/light="
 32    echo "o/opus="
 33    echo "s/sonnet="
 34    echo "k/haiku="
 35    echo "a/agent="
 36end
 37
 38function _synu_agent_claude_env_vars --description "Return list of environment variables set by configure"
 39    echo ANTHROPIC_BASE_URL
 40    echo ANTHROPIC_AUTH_TOKEN
 41    echo ANTHROPIC_DEFAULT_OPUS_MODEL
 42    echo ANTHROPIC_DEFAULT_SONNET_MODEL
 43    echo ANTHROPIC_DEFAULT_HAIKU_MODEL
 44    echo CLAUDE_CODE_SUBAGENT_MODEL
 45    echo CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC
 46end
 47
 48function _synu_agent_claude_configure --description "Configure Claude Code environment variables"
 49    # Parse flags passed from main synu
 50    argparse 'H/heavy=' 'M/medium=' 'l/light=' 'o/opus=' 's/sonnet=' 'k/haiku=' 'a/agent=' -- $argv
 51    or return 1
 52
 53    # Start with defaults (from cache or fallback)
 54    set -l opus_model (_synu_claude_default opus)
 55    set -l sonnet_model (_synu_claude_default sonnet)
 56    set -l haiku_model (_synu_claude_default haiku)
 57    set -l subagent_model (_synu_claude_default agent)
 58
 59    # Apply group overrides
 60    if set -q _flag_heavy
 61        set opus_model $_flag_heavy
 62    end
 63
 64    if set -q _flag_medium
 65        set sonnet_model $_flag_medium
 66        set subagent_model $_flag_medium
 67    end
 68
 69    if set -q _flag_light
 70        set haiku_model $_flag_light
 71    end
 72
 73    # Apply specific overrides (take precedence over groups)
 74    if set -q _flag_opus
 75        set opus_model $_flag_opus
 76    end
 77    if set -q _flag_sonnet
 78        set sonnet_model $_flag_sonnet
 79    end
 80    if set -q _flag_haiku
 81        set haiku_model $_flag_haiku
 82    end
 83    if set -q _flag_agent
 84        set subagent_model $_flag_agent
 85    end
 86
 87    # Export environment variables for Claude Code
 88    set -gx ANTHROPIC_BASE_URL "https://api.synthetic.new/anthropic"
 89    set -gx ANTHROPIC_AUTH_TOKEN $SYNTHETIC_API_KEY
 90    set -gx ANTHROPIC_DEFAULT_OPUS_MODEL $opus_model
 91    set -gx ANTHROPIC_DEFAULT_SONNET_MODEL $sonnet_model
 92    set -gx ANTHROPIC_DEFAULT_HAIKU_MODEL $haiku_model
 93    set -gx CLAUDE_CODE_SUBAGENT_MODEL $subagent_model
 94    set -gx CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC 1
 95end
 96
 97function _synu_agent_claude_interactive --description "Interactive model selection using gum"
 98    # Check for gum
 99    if not command -q gum
100        echo "Error: gum is required for interactive mode. Install: https://github.com/charmbracelet/gum" >&2
101        return 1
102    end
103
104    # Fetch available models
105    set -l models_json (gum spin --spinner dot --title "Fetching models..." -- \
106        curl -s -H "Authorization: Bearer $SYNTHETIC_API_KEY" \
107        "https://api.synthetic.new/openai/v1/models")
108    or return 1
109
110    set -l model_names (echo $models_json | jq -r '.data[].name')
111    or return 1
112
113    # Get current models for display
114    set -l current_opus_id (_synu_claude_default opus)
115    set -l current_sonnet_id (_synu_claude_default sonnet)
116    set -l current_haiku_id (_synu_claude_default haiku)
117    set -l current_agent_id (_synu_claude_default agent)
118    set -l current_opus_name (echo $models_json | \
119        jq -r --arg id "$current_opus_id" '.data[] | select(.id == $id) | .name // "unknown"')
120    set -l current_sonnet_name (echo $models_json | \
121        jq -r --arg id "$current_sonnet_id" '.data[] | select(.id == $id) | .name // "unknown"')
122    set -l current_haiku_name (echo $models_json | \
123        jq -r --arg id "$current_haiku_id" '.data[] | select(.id == $id) | .name // "unknown"')
124    set -l current_agent_name (echo $models_json | \
125        jq -r --arg id "$current_agent_id" '.data[] | select(.id == $id) | .name // "unknown"')
126
127    # Prompt for groups vs individual
128    set -l mode (gum choose --limit 1 --header "How do you want to select models?" \
129        "Groups" "Individual models")
130    or return 1
131
132    # Build flags array
133    set -l flags
134
135    if test "$mode" = "Groups"
136        # Select which groups to override
137        set -l groups (gum choose --no-limit \
138            --header "Which group(s) do you want to override?" \
139            "Heavy (Opus)" "Medium (Sonnet, Sub-agent)" "Light (Haiku)")
140        or return 1
141
142        for group in $groups
143            if test "$group" = "Heavy (Opus)"
144                set -l model_name (printf "%s\n" $model_names | \
145                    gum filter --limit 1 --header "Select model for Heavy group (opus: $current_opus_id)" \
146                    --placeholder "Filter models...")
147                or return 1
148                set -l model_id (echo $models_json | \
149                    jq -r --arg name "$model_name" '.data[] | select(.name == $name) | .id')
150                if test -n "$model_id"
151                    set flags $flags --heavy=$model_id
152                end
153            else if test "$group" = "Medium (Sonnet, Sub-agent)"
154                set -l model_name (printf "%s\n" $model_names | \
155                    gum filter --limit 1 --header "Select model for Medium group (sonnet: $current_sonnet_id, agent: $current_agent_id)" \
156                    --placeholder "Filter models...")
157                or return 1
158                set -l model_id (echo $models_json | \
159                    jq -r --arg name "$model_name" '.data[] | select(.name == $name) | .id')
160                if test -n "$model_id"
161                    set flags $flags --medium=$model_id
162                end
163            else if test "$group" = "Light (Haiku)"
164                set -l model_name (printf "%s\n" $model_names | \
165                    gum filter --limit 1 --header "Select model for Light group (haiku: $current_haiku_id)" \
166                    --placeholder "Filter models...")
167                or return 1
168                set -l model_id (echo $models_json | \
169                    jq -r --arg name "$model_name" '.data[] | select(.name == $name) | .id')
170                if test -n "$model_id"
171                    set flags $flags --light=$model_id
172                end
173            end
174        end
175    else
176        # Select which individual models to override
177        set -l models (gum choose --no-limit \
178            --header "Which model(s) do you want to override?" \
179            "Opus" "Sonnet" "Haiku" "Sub-agent")
180        or return 1
181
182        for model_type in $models
183            switch $model_type
184                case "Opus"
185                    set -l model_name (printf "%s\n" $model_names | \
186                        gum filter --limit 1 --header "Select Opus model (current: $current_opus_id)" \
187                        --placeholder "Filter models...")
188                    or return 1
189                    set -l model_id (echo $models_json | \
190                        jq -r --arg name "$model_name" '.data[] | select(.name == $name) | .id')
191                    if test -n "$model_id"
192                        set flags $flags --opus=$model_id
193                    end
194                case "Sonnet"
195                    set -l model_name (printf "%s\n" $model_names | \
196                        gum filter --limit 1 --header "Select Sonnet model (current: $current_sonnet_id)" \
197                        --placeholder "Filter models...")
198                    or return 1
199                    set -l model_id (echo $models_json | \
200                        jq -r --arg name "$model_name" '.data[] | select(.name == $name) | .id')
201                    if test -n "$model_id"
202                        set flags $flags --sonnet=$model_id
203                    end
204                case "Haiku"
205                    set -l model_name (printf "%s\n" $model_names | \
206                        gum filter --limit 1 --header "Select Haiku model (current: $current_haiku_id)" \
207                        --placeholder "Filter models...")
208                    or return 1
209                    set -l model_id (echo $models_json | \
210                        jq -r --arg name "$model_name" '.data[] | select(.name == $name) | .id')
211                    if test -n "$model_id"
212                        set flags $flags --haiku=$model_id
213                    end
214                case "Sub-agent"
215                    set -l model_name (printf "%s\n" $model_names | \
216                        gum filter --limit 1 --header "Select Sub-agent model (current: $current_agent_id)" \
217                        --placeholder "Filter models...")
218                    or return 1
219                    set -l model_id (echo $models_json | \
220                        jq -r --arg name "$model_name" '.data[] | select(.name == $name) | .id')
221                    if test -n "$model_id"
222                        set flags $flags --agent=$model_id
223                    end
224            end
225        end
226    end
227
228    # Offer to save as defaults
229    if test (count $flags) -gt 0
230        if gum confirm "Save as default for 'claude'?"
231            for flag in $flags
232                # Parse --key=value format
233                set -l parts (string match -r -- '^--([^=]+)=(.+)$' $flag)
234                if test -n "$parts[2]"
235                    set -l key $parts[2]
236                    set -l value $parts[3]
237                    # Expand group flags to individual slots
238                    switch $key
239                        case heavy
240                            _synu_cache_set claude opus $value
241                        case medium
242                            _synu_cache_set claude sonnet $value
243                            _synu_cache_set claude agent $value
244                        case light
245                            _synu_cache_set claude haiku $value
246                        case '*'
247                            _synu_cache_set claude $key $value
248                    end
249                end
250            end
251        end
252    end
253
254    # Output flags for caller to use (one per line for proper array capture)
255    printf '%s\n' $flags
256end