diff --git a/completions/synu.fish b/completions/synu.fish index c737efc9b124e2c8a81851420534e13c269f8e47..e0defd108d91805d6fdcd2a68a3010788e5dfd20 100644 --- a/completions/synu.fish +++ b/completions/synu.fish @@ -4,14 +4,14 @@ # Provide basic usage information for the wrapper itself # Suggest known agents and interactive mode for the first argument -complete -c synu -n "not __fish_seen_subcommand_from i claude crush amp octo codex" \ +complete -c synu -n "not __fish_seen_subcommand_from i claude opencode aider llxprt qwen crush amp octo codex" \ -a "i" -d "Interactive model selection" -complete -c synu -n "not __fish_seen_subcommand_from i claude crush amp octo codex" \ - -a "claude crush amp octo codex" -d "AI agent to wrap" +complete -c synu -n "not __fish_seen_subcommand_from i claude opencode aider llxprt qwen crush amp octo codex" \ + -a "claude opencode aider llxprt qwen crush amp octo codex" -d "AI agent to wrap" # After "i" subcommand, suggest agents -complete -c synu -n "__fish_seen_subcommand_from i; and not __fish_seen_subcommand_from claude crush amp octo codex" \ - -a "claude crush amp octo codex" -d "AI agent" +complete -c synu -n "__fish_seen_subcommand_from i; and not __fish_seen_subcommand_from claude opencode aider llxprt qwen crush amp octo codex" \ + -a "claude opencode aider llxprt qwen crush amp octo codex" -d "AI agent" # Claude-specific flags (when claude is the agent) complete -c synu -n "__fish_seen_subcommand_from claude" \ @@ -29,3 +29,21 @@ complete -c synu -n "__fish_seen_subcommand_from claude" \ # Inherit claude completions for claude subcommand complete -c synu -n "__fish_seen_subcommand_from claude" -w claude + +# OpenCode-specific flags (when opencode is the agent) +complete -c synu -n "__fish_seen_subcommand_from opencode" \ + -s m -l model -r -d "Override model" + +# Aider-specific flags (when aider is the agent) +complete -c synu -n "__fish_seen_subcommand_from aider" \ + -s m -l model -r -d "Main model" +complete -c synu -n "__fish_seen_subcommand_from aider" \ + -s e -l editor-model -r -d "Editor model (enables architect + editor mode)" + +# llxprt-specific flags (when llxprt is the agent) +complete -c synu -n "__fish_seen_subcommand_from llxprt" \ + -s m -l model -r -d "Override model" + +# Qwen Code-specific flags (when qwen is the agent) +complete -c synu -n "__fish_seen_subcommand_from qwen" \ + -s m -l model -r -d "Override model" diff --git a/functions/_synu_agents/aider.fish b/functions/_synu_agents/aider.fish new file mode 100644 index 0000000000000000000000000000000000000000..3b0b4a99b12e21ef40c570db17c8deb0ab125ce9 --- /dev/null +++ b/functions/_synu_agents/aider.fish @@ -0,0 +1,147 @@ +# SPDX-FileCopyrightText: Amolith +# +# SPDX-License-Identifier: Unlicense + +# Aider agent definition for synu +# Provides model configuration for routing through Synthetic API +# Aider accepts model via CLI flags and API config via environment variables + +# Source cache functions +source (status dirname)/../_synu_cache.fish + +# Fallback defaults (used when no cache entry exists) +set -g _synu_aider_fallback_model "hf:MiniMaxAI/MiniMax-M2" +set -g _synu_aider_fallback_editor_model "" + +function _synu_aider_default --description "Get default model: _synu_aider_default slot" + set -l slot $argv[1] + set -l cached (_synu_cache_get aider $slot) + if test $status -eq 0 + echo $cached + else + set -l var_name _synu_aider_fallback_$slot + echo $$var_name + end +end + +function _synu_agent_aider_flags --description "Return argparse-compatible flag specification" + echo "m/model=" + echo "e/editor-model=" +end + +function _synu_agent_aider_env_vars --description "Return list of environment variables set by configure" + echo OPENAI_API_BASE + echo OPENAI_API_KEY +end + +function _synu_agent_aider_configure --description "Configure Aider environment variables and model selection" + # Parse flags passed from main synu + argparse 'm/model=' 'e/editor-model=' -- $argv + or return 1 + + # Start with defaults (from cache or fallback) + set -g _synu_aider_selected_model (_synu_aider_default model) + set -g _synu_aider_selected_editor_model (_synu_aider_default editor_model) + + # Apply overrides if provided + if set -q _flag_model + set -g _synu_aider_selected_model $_flag_model + end + if set -q _flag_editor_model + set -g _synu_aider_selected_editor_model $_flag_editor_model + end + + # Export environment variables for Aider + set -gx OPENAI_API_BASE "https://api.synthetic.new/openai/v1" + set -gx OPENAI_API_KEY $SYNTHETIC_API_KEY +end + +function _synu_agent_aider_args --description "Return CLI arguments to pass to aider" + # Always return --model + echo --model + echo "openai/$_synu_aider_selected_model" + + # Return --editor-model if set + if test -n "$_synu_aider_selected_editor_model" + echo --editor-model + echo "openai/$_synu_aider_selected_editor_model" + end +end + +function _synu_agent_aider_interactive --description "Interactive model selection using gum" + # Check for gum + if not command -q gum + echo "Error: gum is required for interactive mode. Install: https://github.com/charmbracelet/gum" >&2 + return 1 + end + + # Fetch available models + set -l models_json (gum spin --spinner dot --title "Fetching models..." -- \ + curl -s -H "Authorization: Bearer $SYNTHETIC_API_KEY" \ + "https://api.synthetic.new/openai/v1/models") + or return 1 + + set -l model_names (echo $models_json | jq -r '.data[].name') + or return 1 + + # Ask if editor model should be set + set -l use_editor_model (gum choose --limit 1 \ + --header "Aider has two modes. Set editor model?" \ + "No (single model mode)" "Yes (architect + editor mode)") + or return 1 + + # Build flags array + set -l flags + + # Select main model + set -l model_name (printf "%s\n" $model_names | \ + gum filter --limit 1 --header "Select main model for Aider" \ + --placeholder "Filter models...") + or return 1 + + set -l model_id (echo $models_json | \ + jq -r --arg name "$model_name" '.data[] | select(.name == $name) | .id') + + if test -z "$model_id" + echo "Error: Could not find model ID" >&2 + return 1 + end + + set flags $flags --model=$model_id + + # Select editor model if requested + if test "$use_editor_model" = "Yes (architect + editor mode)" + set -l editor_model_name (printf "%s\n" $model_names | \ + gum filter --limit 1 --header "Select editor model for Aider" \ + --placeholder "Filter models...") + or return 1 + + set -l editor_model_id (echo $models_json | \ + jq -r --arg name "$editor_model_name" '.data[] | select(.name == $name) | .id') + + if test -z "$editor_model_id" + echo "Error: Could not find editor model ID" >&2 + return 1 + end + + set flags $flags --editor-model=$editor_model_id + end + + # Offer to save as defaults + if gum confirm "Save as default for 'aider'?" + for flag in $flags + # Parse --key=value format + set -l parts (string match -r -- '^--([^=]+)=(.+)$' $flag) + if test -n "$parts[2]" + set -l key $parts[2] + set -l value $parts[3] + # Replace hyphens with underscores for cache keys + set key (string replace -a '-' '_' $key) + _synu_cache_set aider $key $value + end + end + end + + # Output flags for caller to use + echo $flags +end diff --git a/functions/_synu_agents/llxprt.fish b/functions/_synu_agents/llxprt.fish new file mode 100644 index 0000000000000000000000000000000000000000..efb6a9e1258dc10db2980a4417cfbe76b559bad4 --- /dev/null +++ b/functions/_synu_agents/llxprt.fish @@ -0,0 +1,92 @@ +# SPDX-FileCopyrightText: Amolith +# +# SPDX-License-Identifier: Unlicense + +# llxprt agent definition for synu +# Provides model configuration for routing through Synthetic API +# llxprt only accepts configuration via CLI flags + +# Source cache functions +source (status dirname)/../_synu_cache.fish + +# Fallback default (used when no cache entry exists) +set -g _synu_llxprt_fallback_model "hf:MiniMaxAI/MiniMax-M2" + +function _synu_llxprt_default --description "Get default model" + set -l cached (_synu_cache_get llxprt model) + if test $status -eq 0 + echo $cached + else + echo $_synu_llxprt_fallback_model + end +end + +function _synu_agent_llxprt_flags --description "Return argparse-compatible flag specification" + echo "m/model=" +end + +function _synu_agent_llxprt_configure --description "Configure llxprt model selection" + # Parse flags passed from main synu + argparse 'm/model=' -- $argv + or return 1 + + # Start with default (from cache or fallback) + set -g _synu_llxprt_selected_model (_synu_llxprt_default) + + # Apply override if provided + if set -q _flag_model + set -g _synu_llxprt_selected_model $_flag_model + end +end + +function _synu_agent_llxprt_args --description "Return CLI arguments to pass to llxprt" + # Return --provider, --baseurl, and --model flags + echo --provider + echo openai + echo --baseurl + echo "https://api.synthetic.new/openai/v1" + echo --model + echo $_synu_llxprt_selected_model +end + +function _synu_agent_llxprt_interactive --description "Interactive model selection using gum" + # Check for gum + if not command -q gum + echo "Error: gum is required for interactive mode. Install: https://github.com/charmbracelet/gum" >&2 + return 1 + end + + # Fetch available models + set -l models_json (gum spin --spinner dot --title "Fetching models..." -- \ + curl -s -H "Authorization: Bearer $SYNTHETIC_API_KEY" \ + "https://api.synthetic.new/openai/v1/models") + or return 1 + + set -l model_names (echo $models_json | jq -r '.data[].name') + or return 1 + + # Select model + set -l model_name (printf "%s\n" $model_names | \ + gum filter --limit 1 --header "Select model for llxprt" \ + --placeholder "Filter models...") + or return 1 + + set -l model_id (echo $models_json | \ + jq -r --arg name "$model_name" '.data[] | select(.name == $name) | .id') + + if test -z "$model_id" + echo "Error: Could not find model ID" >&2 + return 1 + end + + # Build flags + set -l flags --model=$model_id + + # Offer to save as default + if gum confirm "Save as default for 'llxprt'?" + _synu_cache_set llxprt model $model_id + end + + # Output flags for caller to use + echo $flags +end diff --git a/functions/_synu_agents/qwen.fish b/functions/_synu_agents/qwen.fish new file mode 100644 index 0000000000000000000000000000000000000000..e1b234b44fc6133eaa8bfd4ecdd8ba3e77377ce5 --- /dev/null +++ b/functions/_synu_agents/qwen.fish @@ -0,0 +1,93 @@ +# SPDX-FileCopyrightText: Amolith +# +# SPDX-License-Identifier: Unlicense + +# Qwen Code agent definition for synu +# Provides model configuration for routing through Synthetic API +# Qwen Code only accepts configuration via environment variables + +# Source cache functions +source (status dirname)/../_synu_cache.fish + +# Fallback default (used when no cache entry exists) +set -g _synu_qwen_fallback_model "hf:MiniMaxAI/MiniMax-M2" + +function _synu_qwen_default --description "Get default model" + set -l cached (_synu_cache_get qwen model) + if test $status -eq 0 + echo $cached + else + echo $_synu_qwen_fallback_model + end +end + +function _synu_agent_qwen_flags --description "Return argparse-compatible flag specification" + echo "m/model=" +end + +function _synu_agent_qwen_env_vars --description "Return list of environment variables set by configure" + echo OPENAI_API_KEY + echo OPENAI_BASE_URL + echo OPENAI_MODEL +end + +function _synu_agent_qwen_configure --description "Configure Qwen Code environment variables" + # Parse flags passed from main synu + argparse 'm/model=' -- $argv + or return 1 + + # Start with default (from cache or fallback) + set -l model (_synu_qwen_default) + + # Apply override if provided + if set -q _flag_model + set model $_flag_model + end + + # Export environment variables for Qwen Code + set -gx OPENAI_API_KEY $SYNTHETIC_API_KEY + set -gx OPENAI_BASE_URL "https://api.synthetic.new/openai/v1" + set -gx OPENAI_MODEL $model +end + +function _synu_agent_qwen_interactive --description "Interactive model selection using gum" + # Check for gum + if not command -q gum + echo "Error: gum is required for interactive mode. Install: https://github.com/charmbracelet/gum" >&2 + return 1 + end + + # Fetch available models + set -l models_json (gum spin --spinner dot --title "Fetching models..." -- \ + curl -s -H "Authorization: Bearer $SYNTHETIC_API_KEY" \ + "https://api.synthetic.new/openai/v1/models") + or return 1 + + set -l model_names (echo $models_json | jq -r '.data[].name') + or return 1 + + # Select model + set -l model_name (printf "%s\n" $model_names | \ + gum filter --limit 1 --header "Select model for Qwen Code" \ + --placeholder "Filter models...") + or return 1 + + set -l model_id (echo $models_json | \ + jq -r --arg name "$model_name" '.data[] | select(.name == $name) | .id') + + if test -z "$model_id" + echo "Error: Could not find model ID" >&2 + return 1 + end + + # Build flags + set -l flags --model=$model_id + + # Offer to save as default + if gum confirm "Save as default for 'qwen'?" + _synu_cache_set qwen model $model_id + end + + # Output flags for caller to use + echo $flags +end