diff --git a/codeagent-wrapper/backend.go b/codeagent-wrapper/backend.go index 9afc0c1..d3bac4a 100644 --- a/codeagent-wrapper/backend.go +++ b/codeagent-wrapper/backend.go @@ -4,6 +4,7 @@ import ( "encoding/json" "os" "path/filepath" + "strings" ) // Backend defines the contract for invoking different AI CLI backends. @@ -120,7 +121,16 @@ func buildGeminiArgs(cfg *Config, targetArg string) []string { if cfg == nil { return nil } - args := []string{"--output-format", "stream-json", "-y"} + + args := []string{} + + // Add model parameter first (if specified) + if model := strings.TrimSpace(cfg.GeminiModel); model != "" { + args = append(args, "-m", model) + } + + // Existing args + args = append(args, "-o", "stream-json", "-y") if cfg.Mode == "resume" { if cfg.SessionID != "" { diff --git a/codeagent-wrapper/config.go b/codeagent-wrapper/config.go index 9524770..1ff3486 100644 --- a/codeagent-wrapper/config.go +++ b/codeagent-wrapper/config.go @@ -20,6 +20,7 @@ type Config struct { Backend string SkipPermissions bool MaxParallelWorkers int + GeminiModel string // Gemini model name (empty = use default) } // ParallelConfig defines the JSON schema for parallel execution @@ -197,6 +198,9 @@ func parseArgs() (*Config, error) { return nil, fmt.Errorf("task required") } + // Read environment variable (lowest precedence) + geminiModel := strings.TrimSpace(os.Getenv("GEMINI_MODEL")) + backendName := defaultBackendName skipPermissions := envFlagEnabled("CODEAGENT_SKIP_PERMISSIONS") filtered := make([]string, 0, len(args)) @@ -220,6 +224,24 @@ func parseArgs() (*Config, error) { } backendName = value continue + case arg == "--gemini-model": + if i+1 >= len(args) { + return nil, fmt.Errorf("--gemini-model flag requires a non-empty model name") + } + value := strings.TrimSpace(args[i+1]) + if value == "" { + return nil, fmt.Errorf("--gemini-model flag requires a non-empty model name") + } + geminiModel = value + i++ + continue + case strings.HasPrefix(arg, "--gemini-model="): + value := strings.TrimSpace(strings.TrimPrefix(arg, "--gemini-model=")) + if value == "" { + return nil, fmt.Errorf("--gemini-model flag requires a non-empty model name") + } + geminiModel = value + continue case arg == "--skip-permissions", arg == "--dangerously-skip-permissions": skipPermissions = true continue @@ -238,7 +260,7 @@ func parseArgs() (*Config, error) { } args = filtered - cfg := &Config{WorkDir: defaultWorkdir, Backend: backendName, SkipPermissions: skipPermissions} + cfg := &Config{WorkDir: defaultWorkdir, Backend: backendName, SkipPermissions: skipPermissions, GeminiModel: geminiModel} cfg.MaxParallelWorkers = resolveMaxParallelWorkers() if args[0] == "resume" { diff --git a/codeagent-wrapper/main.go b/codeagent-wrapper/main.go index 49a7488..9f7179e 100644 --- a/codeagent-wrapper/main.go +++ b/codeagent-wrapper/main.go @@ -14,7 +14,7 @@ import ( ) const ( - version = "5.7.1" + version = "5.7.2" defaultWorkdir = "." defaultTimeout = 7200 // seconds (2 hours) defaultCoverageTarget = 90.0 @@ -197,6 +197,9 @@ func run() (exitCode int) { fullOutput := false var extras []string + // Check for gemini-model in parallel mode + geminiModelInParallel := false + for i := 0; i < len(args); i++ { arg := args[i] switch { @@ -218,11 +221,19 @@ func run() (exitCode int) { return 1 } backendName = value + case arg == "--gemini-model" || strings.HasPrefix(arg, "--gemini-model="): + geminiModelInParallel = true + continue default: extras = append(extras, arg) } } + // Warn about unsupported parameter + if geminiModelInParallel { + logWarn("--gemini-model parameter is not supported in parallel mode") + } + if len(extras) > 0 { fmt.Fprintln(os.Stderr, "ERROR: --parallel reads its task configuration from stdin; only --backend and --full-output are allowed.") fmt.Fprintln(os.Stderr, "Usage examples:") @@ -322,6 +333,14 @@ func run() (exitCode int) { } logInfo(fmt.Sprintf("Parsed args: mode=%s, task_len=%d, backend=%s", cfg.Mode, len(cfg.Task), cfg.Backend)) + // Log environment variable usage + if cfg.GeminiModel != "" { + envModel := strings.TrimSpace(os.Getenv("GEMINI_MODEL")) + if envModel != "" && envModel == cfg.GeminiModel { + logInfo(fmt.Sprintf("Gemini model from env: %s", cfg.GeminiModel)) + } + } + backend, err := selectBackendFn(cfg.Backend) if err != nil { logError(err.Error()) @@ -342,6 +361,16 @@ func run() (exitCode int) { } logInfo(fmt.Sprintf("Selected backend: %s", backend.Name())) + // Log model parameter usage + if cfg.GeminiModel != "" && cfg.Backend == "gemini" { + logInfo(fmt.Sprintf("Using Gemini model: %s", cfg.GeminiModel)) + } + + // Warn if model parameter used with non-gemini backend + if cfg.GeminiModel != "" && cfg.Backend != "gemini" { + logWarn("--gemini-model parameter is only effective with --backend gemini") + } + timeoutSec := resolveTimeout() logInfo(fmt.Sprintf("Timeout: %ds", timeoutSec)) cfg.Timeout = timeoutSec @@ -532,6 +561,10 @@ Parallel mode examples: Options: --lite, -L Lite mode: disable Web UI, faster response --backend Select backend (codex, gemini, claude) + --gemini-model Specify Gemini model (gemini backend only) + Can also be set via GEMINI_MODEL environment variable + CLI parameter takes precedence over environment variable + Examples: gemini-2.5-flash, gemini-1.5-pro Environment Variables: CODEX_TIMEOUT Timeout in milliseconds (default: 7200000)