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 "L/large="
30 echo "l/light="
31 echo "o/opus="
32 echo "s/sonnet="
33 echo "H/haiku="
34 echo "a/agent="
35end
36
37function _synu_agent_claude_env_vars --description "Return list of environment variables set by configure"
38 echo ANTHROPIC_BASE_URL
39 echo ANTHROPIC_AUTH_TOKEN
40 echo ANTHROPIC_DEFAULT_OPUS_MODEL
41 echo ANTHROPIC_DEFAULT_SONNET_MODEL
42 echo ANTHROPIC_DEFAULT_HAIKU_MODEL
43 echo CLAUDE_CODE_SUBAGENT_MODEL
44 echo CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC
45end
46
47function _synu_agent_claude_configure --description "Configure Claude Code environment variables"
48 # Parse flags passed from main synu
49 argparse 'L/large=' 'l/light=' 'o/opus=' 's/sonnet=' 'H/haiku=' 'a/agent=' -- $argv
50 or return 1
51
52 # Start with defaults (from cache or fallback)
53 set -l opus_model (_synu_claude_default opus)
54 set -l sonnet_model (_synu_claude_default sonnet)
55 set -l haiku_model (_synu_claude_default haiku)
56 set -l subagent_model (_synu_claude_default agent)
57
58 # Apply group overrides
59 if set -q _flag_large
60 set opus_model $_flag_large
61 set sonnet_model $_flag_large
62 set subagent_model $_flag_large
63 end
64
65 if set -q _flag_light
66 set haiku_model $_flag_light
67 end
68
69 # Apply specific overrides (take precedence over groups)
70 if set -q _flag_opus
71 set opus_model $_flag_opus
72 end
73 if set -q _flag_sonnet
74 set sonnet_model $_flag_sonnet
75 end
76 if set -q _flag_haiku
77 set haiku_model $_flag_haiku
78 end
79 if set -q _flag_agent
80 set subagent_model $_flag_agent
81 end
82
83 # Export environment variables for Claude Code
84 set -gx ANTHROPIC_BASE_URL "https://api.synthetic.new/anthropic"
85 set -gx ANTHROPIC_AUTH_TOKEN $SYNTHETIC_API_KEY
86 set -gx ANTHROPIC_DEFAULT_OPUS_MODEL $opus_model
87 set -gx ANTHROPIC_DEFAULT_SONNET_MODEL $sonnet_model
88 set -gx ANTHROPIC_DEFAULT_HAIKU_MODEL $haiku_model
89 set -gx CLAUDE_CODE_SUBAGENT_MODEL $subagent_model
90 set -gx CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC 1
91end
92
93function _synu_agent_claude_interactive --description "Interactive model selection using gum"
94 # Check for gum
95 if not command -q gum
96 echo "Error: gum is required for interactive mode. Install: https://github.com/charmbracelet/gum" >&2
97 return 1
98 end
99
100 # Fetch available models
101 set -l models_json (gum spin --spinner dot --title "Fetching models..." -- \
102 curl -s -H "Authorization: Bearer $SYNTHETIC_API_KEY" \
103 "https://api.synthetic.new/openai/v1/models")
104 or return 1
105
106 set -l model_names (echo $models_json | jq -r '.data[].name')
107 or return 1
108
109 # Get current models for display
110 set -l current_opus_id (_synu_claude_default opus)
111 set -l current_sonnet_id (_synu_claude_default sonnet)
112 set -l current_haiku_id (_synu_claude_default haiku)
113 set -l current_agent_id (_synu_claude_default agent)
114 set -l current_opus_name (echo $models_json | \
115 jq -r --arg id "$current_opus_id" '.data[] | select(.id == $id) | .name // "unknown"')
116 set -l current_sonnet_name (echo $models_json | \
117 jq -r --arg id "$current_sonnet_id" '.data[] | select(.id == $id) | .name // "unknown"')
118 set -l current_haiku_name (echo $models_json | \
119 jq -r --arg id "$current_haiku_id" '.data[] | select(.id == $id) | .name // "unknown"')
120 set -l current_agent_name (echo $models_json | \
121 jq -r --arg id "$current_agent_id" '.data[] | select(.id == $id) | .name // "unknown"')
122
123 # Prompt for groups vs individual
124 set -l mode (gum choose --limit 1 --header "How do you want to select models?" \
125 "Groups" "Individual models")
126 or return 1
127
128 # Build flags array
129 set -l flags
130
131 if test "$mode" = "Groups"
132 # Select which groups to override
133 set -l groups (gum choose --no-limit \
134 --header "Which group(s) do you want to override?" \
135 "Large (Opus, Sonnet, Sub-agent)" "Light (Haiku)")
136 or return 1
137
138 for group in $groups
139 if test "$group" = "Large (Opus, Sonnet, Sub-agent)"
140 set -l model_name (printf "%s\n" $model_names | \
141 gum filter --limit 1 --header "Select model for Large group (opus: $current_opus_id, sonnet: $current_sonnet_id, agent: $current_agent_id)" \
142 --placeholder "Filter models...")
143 or return 1
144 set -l model_id (echo $models_json | \
145 jq -r --arg name "$model_name" '.data[] | select(.name == $name) | .id')
146 if test -n "$model_id"
147 set flags $flags --large=$model_id
148 end
149 else if test "$group" = "Light (Haiku)"
150 set -l model_name (printf "%s\n" $model_names | \
151 gum filter --limit 1 --header "Select model for Light group (haiku: $current_haiku_id)" \
152 --placeholder "Filter models...")
153 or return 1
154 set -l model_id (echo $models_json | \
155 jq -r --arg name "$model_name" '.data[] | select(.name == $name) | .id')
156 if test -n "$model_id"
157 set flags $flags --light=$model_id
158 end
159 end
160 end
161 else
162 # Select which individual models to override
163 set -l models (gum choose --no-limit \
164 --header "Which model(s) do you want to override?" \
165 "Opus" "Sonnet" "Haiku" "Sub-agent")
166 or return 1
167
168 for model_type in $models
169 switch $model_type
170 case "Opus"
171 set -l model_name (printf "%s\n" $model_names | \
172 gum filter --limit 1 --header "Select Opus model (current: $current_opus_id)" \
173 --placeholder "Filter models...")
174 or return 1
175 set -l model_id (echo $models_json | \
176 jq -r --arg name "$model_name" '.data[] | select(.name == $name) | .id')
177 if test -n "$model_id"
178 set flags $flags --opus=$model_id
179 end
180 case "Sonnet"
181 set -l model_name (printf "%s\n" $model_names | \
182 gum filter --limit 1 --header "Select Sonnet model (current: $current_sonnet_id)" \
183 --placeholder "Filter models...")
184 or return 1
185 set -l model_id (echo $models_json | \
186 jq -r --arg name "$model_name" '.data[] | select(.name == $name) | .id')
187 if test -n "$model_id"
188 set flags $flags --sonnet=$model_id
189 end
190 case "Haiku"
191 set -l model_name (printf "%s\n" $model_names | \
192 gum filter --limit 1 --header "Select Haiku model (current: $current_haiku_id)" \
193 --placeholder "Filter models...")
194 or return 1
195 set -l model_id (echo $models_json | \
196 jq -r --arg name "$model_name" '.data[] | select(.name == $name) | .id')
197 if test -n "$model_id"
198 set flags $flags --haiku=$model_id
199 end
200 case "Sub-agent"
201 set -l model_name (printf "%s\n" $model_names | \
202 gum filter --limit 1 --header "Select Sub-agent model (current: $current_agent_id)" \
203 --placeholder "Filter models...")
204 or return 1
205 set -l model_id (echo $models_json | \
206 jq -r --arg name "$model_name" '.data[] | select(.name == $name) | .id')
207 if test -n "$model_id"
208 set flags $flags --agent=$model_id
209 end
210 end
211 end
212 end
213
214 # Offer to save as defaults
215 if test (count $flags) -gt 0
216 if gum confirm "Save as default for 'claude'?"
217 for flag in $flags
218 # Parse --key=value format
219 set -l parts (string match -r -- '^--([^=]+)=(.+)$' $flag)
220 if test -n "$parts[2]"
221 set -l key $parts[2]
222 set -l value $parts[3]
223 # Expand group flags to individual slots
224 switch $key
225 case large
226 _synu_cache_set claude opus $value
227 _synu_cache_set claude sonnet $value
228 _synu_cache_set claude agent $value
229 case light
230 _synu_cache_set claude haiku $value
231 case '*'
232 _synu_cache_set claude $key $value
233 end
234 end
235 end
236 end
237 end
238
239 # Output flags for caller to use (one per line for proper array capture)
240 printf '%s\n' $flags
241end