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