package config import ( "fmt" "os" "os/exec" "strings" "github.com/ollama/ollama/envconfig" "golang.org/x/mod/semver" ) // Codex implements Runner for Codex integration type Codex struct{} func (c *Codex) String() string { return "Codex" } func (c *Codex) args(model string, extra []string) []string { args := []string{"--oss"} if model != "" { args = append(args, "-m", model) } args = append(args, extra...) return args } func (c *Codex) Run(model string, args []string) error { if err := checkCodexVersion(); err != nil { return err } cmd := exec.Command("codex", c.args(model, args)...) cmd.Stdin = os.Stdin cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr cmd.Env = append(os.Environ(), "OPENAI_BASE_URL="+envconfig.Host().String()+"/v1/", "OPENAI_API_KEY=ollama", ) return cmd.Run() } func checkCodexVersion() error { if _, err := exec.LookPath("codex"); err != nil { return fmt.Errorf("codex is not installed, install with: npm install -g @openai/codex") } out, err := exec.Command("codex", "--version").Output() if err != nil { return fmt.Errorf("failed to get codex version: %w", err) } // Parse output like "codex-cli 0.87.0" fields := strings.Fields(strings.TrimSpace(string(out))) if len(fields) < 2 { return fmt.Errorf("unexpected codex version output: %s", string(out)) } version := "v" + fields[len(fields)-1] minVersion := "v0.81.0" if semver.Compare(version, minVersion) < 0 { return fmt.Errorf("codex version %s is too old, minimum required is %s, update with: npm update -g @openai/codex", fields[len(fields)-1], "0.81.0") } return nil }