diff options
| author | Paul Buetow <paul@buetow.org> | 2025-11-02 23:42:15 +0200 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2025-11-02 23:42:15 +0200 |
| commit | 35e1de6f975088ade5dbf0af533fe6fdac8fcc94 (patch) | |
| tree | c9fc9b6ad86cc10a777b3f510c3c4b2d62c41ebd /docs/coverage.html | |
| parent | c60d5703d25b7d76d1da2f368b0632f08a161644 (diff) | |
some linter fixes
Diffstat (limited to 'docs/coverage.html')
| -rw-r--r-- | docs/coverage.html | 3593 |
1 files changed, 2663 insertions, 930 deletions
diff --git a/docs/coverage.html b/docs/coverage.html index 36775ce..4526ad1 100644 --- a/docs/coverage.html +++ b/docs/coverage.html @@ -55,13 +55,13 @@ <div id="nav"> <select id="files"> - <option value="file0">codeberg.org/snonux/hexai/cmd/hexai-lsp/main.go (75.0%)</option> + <option value="file0">codeberg.org/snonux/hexai/cmd/hexai-lsp/main.go (73.3%)</option> <option value="file1">codeberg.org/snonux/hexai/cmd/hexai-tmux-action/main.go (0.0%)</option> - <option value="file2">codeberg.org/snonux/hexai/cmd/hexai/main.go (71.4%)</option> + <option value="file2">codeberg.org/snonux/hexai/cmd/hexai/main.go (61.9%)</option> - <option value="file3">codeberg.org/snonux/hexai/internal/appconfig/config.go (88.9%)</option> + <option value="file3">codeberg.org/snonux/hexai/internal/appconfig/config.go (82.5%)</option> <option value="file4">codeberg.org/snonux/hexai/internal/editor/editor.go (58.3%)</option> @@ -69,9 +69,9 @@ <option value="file6">codeberg.org/snonux/hexai/internal/hexaiaction/parse.go (92.6%)</option> - <option value="file7">codeberg.org/snonux/hexai/internal/hexaiaction/prompts.go (92.0%)</option> + <option value="file7">codeberg.org/snonux/hexai/internal/hexaiaction/prompts.go (92.3%)</option> - <option value="file8">codeberg.org/snonux/hexai/internal/hexaiaction/run.go (76.8%)</option> + <option value="file8">codeberg.org/snonux/hexai/internal/hexaiaction/run.go (71.1%)</option> <option value="file9">codeberg.org/snonux/hexai/internal/hexaiaction/tui.go (65.5%)</option> @@ -79,65 +79,67 @@ <option value="file11">codeberg.org/snonux/hexai/internal/hexaiaction/tui_delegate.go (100.0%)</option> - <option value="file12">codeberg.org/snonux/hexai/internal/hexaicli/run.go (90.0%)</option> + <option value="file12">codeberg.org/snonux/hexai/internal/hexaicli/run.go (72.3%)</option> - <option value="file13">codeberg.org/snonux/hexai/internal/hexailsp/run.go (90.8%)</option> + <option value="file13">codeberg.org/snonux/hexai/internal/hexailsp/run.go (88.9%)</option> <option value="file14">codeberg.org/snonux/hexai/internal/llm/copilot.go (82.4%)</option> <option value="file15">codeberg.org/snonux/hexai/internal/llm/ollama.go (89.8%)</option> - <option value="file16">codeberg.org/snonux/hexai/internal/llm/openai.go (86.4%)</option> + <option value="file16">codeberg.org/snonux/hexai/internal/llm/openai.go (87.1%)</option> - <option value="file17">codeberg.org/snonux/hexai/internal/llm/provider.go (100.0%)</option> + <option value="file17">codeberg.org/snonux/hexai/internal/llm/openrouter.go (76.2%)</option> - <option value="file18">codeberg.org/snonux/hexai/internal/llm/util.go (100.0%)</option> + <option value="file18">codeberg.org/snonux/hexai/internal/llm/provider.go (86.0%)</option> - <option value="file19">codeberg.org/snonux/hexai/internal/llmutils/client.go (100.0%)</option> + <option value="file19">codeberg.org/snonux/hexai/internal/llm/util.go (100.0%)</option> - <option value="file20">codeberg.org/snonux/hexai/internal/logging/chatlogger.go (100.0%)</option> + <option value="file20">codeberg.org/snonux/hexai/internal/llmutils/client.go (100.0%)</option> - <option value="file21">codeberg.org/snonux/hexai/internal/logging/logging.go (90.9%)</option> + <option value="file21">codeberg.org/snonux/hexai/internal/logging/chatlogger.go (100.0%)</option> - <option value="file22">codeberg.org/snonux/hexai/internal/lsp/chat_commands.go (72.2%)</option> + <option value="file22">codeberg.org/snonux/hexai/internal/logging/logging.go (90.9%)</option> - <option value="file23">codeberg.org/snonux/hexai/internal/lsp/context.go (74.4%)</option> + <option value="file23">codeberg.org/snonux/hexai/internal/lsp/chat_commands.go (83.3%)</option> - <option value="file24">codeberg.org/snonux/hexai/internal/lsp/document.go (91.5%)</option> + <option value="file24">codeberg.org/snonux/hexai/internal/lsp/context.go (74.4%)</option> - <option value="file25">codeberg.org/snonux/hexai/internal/lsp/handlers.go (92.2%)</option> + <option value="file25">codeberg.org/snonux/hexai/internal/lsp/document.go (91.5%)</option> - <option value="file26">codeberg.org/snonux/hexai/internal/lsp/handlers_codeaction.go (84.1%)</option> + <option value="file26">codeberg.org/snonux/hexai/internal/lsp/handlers.go (89.8%)</option> - <option value="file27">codeberg.org/snonux/hexai/internal/lsp/handlers_completion.go (88.8%)</option> + <option value="file27">codeberg.org/snonux/hexai/internal/lsp/handlers_codeaction.go (82.0%)</option> - <option value="file28">codeberg.org/snonux/hexai/internal/lsp/handlers_document.go (77.7%)</option> + <option value="file28">codeberg.org/snonux/hexai/internal/lsp/handlers_completion.go (79.0%)</option> - <option value="file29">codeberg.org/snonux/hexai/internal/lsp/handlers_execute.go (75.0%)</option> + <option value="file29">codeberg.org/snonux/hexai/internal/lsp/handlers_document.go (78.1%)</option> - <option value="file30">codeberg.org/snonux/hexai/internal/lsp/handlers_init.go (66.7%)</option> + <option value="file30">codeberg.org/snonux/hexai/internal/lsp/handlers_execute.go (75.0%)</option> - <option value="file31">codeberg.org/snonux/hexai/internal/lsp/handlers_utils.go (90.2%)</option> + <option value="file31">codeberg.org/snonux/hexai/internal/lsp/handlers_init.go (66.7%)</option> - <option value="file32">codeberg.org/snonux/hexai/internal/lsp/server.go (86.8%)</option> + <option value="file32">codeberg.org/snonux/hexai/internal/lsp/handlers_utils.go (85.3%)</option> - <option value="file33">codeberg.org/snonux/hexai/internal/lsp/transport.go (73.0%)</option> + <option value="file33">codeberg.org/snonux/hexai/internal/lsp/server.go (82.1%)</option> - <option value="file34">codeberg.org/snonux/hexai/internal/runtimeconfig/store.go (87.1%)</option> + <option value="file34">codeberg.org/snonux/hexai/internal/lsp/transport.go (73.0%)</option> - <option value="file35">codeberg.org/snonux/hexai/internal/stats/lock_posix.go (83.3%)</option> + <option value="file35">codeberg.org/snonux/hexai/internal/runtimeconfig/store.go (88.1%)</option> - <option value="file36">codeberg.org/snonux/hexai/internal/stats/stats.go (75.8%)</option> + <option value="file36">codeberg.org/snonux/hexai/internal/stats/lock_posix.go (83.3%)</option> - <option value="file37">codeberg.org/snonux/hexai/internal/testutil/fixtures.go (100.0%)</option> + <option value="file37">codeberg.org/snonux/hexai/internal/stats/stats.go (75.8%)</option> - <option value="file38">codeberg.org/snonux/hexai/internal/textutil/human.go (92.3%)</option> + <option value="file38">codeberg.org/snonux/hexai/internal/testutil/fixtures.go (100.0%)</option> - <option value="file39">codeberg.org/snonux/hexai/internal/textutil/textutil.go (90.4%)</option> + <option value="file39">codeberg.org/snonux/hexai/internal/textutil/human.go (92.3%)</option> - <option value="file40">codeberg.org/snonux/hexai/internal/tmux/status.go (76.7%)</option> + <option value="file40">codeberg.org/snonux/hexai/internal/textutil/textutil.go (90.4%)</option> - <option value="file41">codeberg.org/snonux/hexai/internal/tmux/tmux.go (88.6%)</option> + <option value="file41">codeberg.org/snonux/hexai/internal/tmux/status.go (76.7%)</option> + + <option value="file42">codeberg.org/snonux/hexai/internal/tmux/tmux.go (88.6%)</option> </select> </div> @@ -165,15 +167,20 @@ package main import ( "flag" + "fmt" "log" "os" + "strings" "codeberg.org/snonux/hexai/internal" + "codeberg.org/snonux/hexai/internal/appconfig" "codeberg.org/snonux/hexai/internal/hexailsp" ) func main() <span class="cov8" title="1">{ logPath := flag.String("log", "/tmp/hexai-lsp.log", "path to log file (optional)") + defaultCfg := defaultConfigPath() + configPath := flag.String("config", "", fmt.Sprintf("path to config file (default: %s)", defaultCfg)) showVersion := flag.Bool("version", false, "print version and exit") flag.Parse() if *showVersion </span><span class="cov8" title="1">{ @@ -181,10 +188,19 @@ func main() <span class="cov8" title="1">{ return }</span> - <span class="cov0" title="0">if err := hexailsp.Run(*logPath, os.Stdin, os.Stdout, os.Stderr); err != nil </span><span class="cov0" title="0">{ + <span class="cov0" title="0">path := strings.TrimSpace(*configPath) + if err := hexailsp.RunWithConfig(*logPath, path, os.Stdin, os.Stdout, os.Stderr); err != nil </span><span class="cov0" title="0">{ log.Fatalf("server error: %v", err) }</span> } + +func defaultConfigPath() string <span class="cov8" title="1">{ + path, err := appconfig.ConfigPath() + if err != nil </span><span class="cov0" title="0">{ + return "$XDG_CONFIG_HOME/hexai/config.toml" + }</span> + <span class="cov8" title="1">return path</span> +} </pre> <pre class="file" id="file1" style="display: none">package main @@ -194,7 +210,9 @@ import ( "flag" "fmt" "os" + "strings" + "codeberg.org/snonux/hexai/internal/appconfig" "codeberg.org/snonux/hexai/internal/hexaiaction" ) @@ -202,6 +220,8 @@ func main() <span class="cov0" title="0">{ infile := flag.String("infile", "", "Read input from this file instead of stdin") outfile := flag.String("outfile", "", "Write output to this file instead of stdout") uiChild := flag.Bool("ui-child", false, "INTERNAL: run interactive UI and write to -outfile atomically") + defaultPath := defaultConfigPath() + configPath := flag.String("config", "", fmt.Sprintf("path to config file (default: %s)", defaultPath)) tmuxTarget := flag.String("tmux-target", "", "tmux split target (advanced)") tmuxSplit := flag.String("tmux-split", "v", "tmux split orientation: v or h") tmuxPercent := flag.Int("tmux-percent", 33, "tmux split size percentage (1-100)") @@ -211,11 +231,23 @@ func main() <span class="cov0" title="0">{ Infile: *infile, Outfile: *outfile, UIChild: *uiChild, TmuxTarget: *tmuxTarget, TmuxSplit: *tmuxSplit, TmuxPercent: *tmuxPercent, } - if err := hexaiaction.RunCommand(context.Background(), opts, os.Stdin, os.Stdout, os.Stderr); err != nil </span><span class="cov0" title="0">{ + ctx := context.Background() + if path := strings.TrimSpace(*configPath); path != "" </span><span class="cov0" title="0">{ + ctx = hexaiaction.WithConfigPath(ctx, path) + }</span> + <span class="cov0" title="0">if err := hexaiaction.RunCommand(ctx, opts, os.Stdin, os.Stdout, os.Stderr); err != nil </span><span class="cov0" title="0">{ fmt.Fprintln(os.Stderr, err) os.Exit(1) }</span> } + +func defaultConfigPath() string <span class="cov0" title="0">{ + path, err := appconfig.ConfigPath() + if err != nil </span><span class="cov0" title="0">{ + return "$XDG_CONFIG_HOME/hexai/config.toml" + }</span> + <span class="cov0" title="0">return path</span> +} </pre> <pre class="file" id="file2" style="display: none">// Summary: Hexai CLI entrypoint; parses flags and delegates to internal/hexaicli. @@ -225,24 +257,115 @@ import ( "context" "flag" "fmt" + "io" + "log" "os" + "strconv" + "strings" "codeberg.org/snonux/hexai/internal" + "codeberg.org/snonux/hexai/internal/appconfig" "codeberg.org/snonux/hexai/internal/hexaicli" ) func main() <span class="cov8" title="1">{ - showVersion := flag.Bool("version", false, "print version and exit") - flag.Parse() + configPath, remaining := splitConfigPath(os.Args[1:]) + logger := log.New(io.Discard, "", 0) + cfg := appconfig.LoadWithOptions(logger, appconfig.LoadOptions{ConfigPath: configPath}) + cliEntries := cfg.CLIConfigs + if len(cliEntries) == 0 </span><span class="cov8" title="1">{ + cliEntries = []appconfig.SurfaceConfig{{Provider: cfg.Provider}} + }</span> + <span class="cov8" title="1">fs := flag.NewFlagSet(os.Args[0], flag.ExitOnError) + defaultPath := defaultConfigPath() + configFlag := fs.String("config", configPath, fmt.Sprintf("path to config file (default: %s)", defaultPath)) + showVersion := fs.Bool("version", false, "print version and exit") + selectedFlags := make([]bool, len(cliEntries)) + for i, entry := range cliEntries </span><span class="cov8" title="1">{ + name := strconv.Itoa(i) + provider := strings.TrimSpace(entry.Provider) + if provider == "" </span><span class="cov8" title="1">{ + provider = cfg.Provider + }</span> + <span class="cov8" title="1">model := strings.TrimSpace(entry.Model) + if model == "" </span><span class="cov8" title="1">{ + model = pickDefaultModel(cfg, provider) + }</span> + <span class="cov8" title="1">desc := fmt.Sprintf("use only provider #%d (%s:%s)", i, provider, model) + fs.BoolVar(&selectedFlags[i], name, false, desc)</span> + } + <span class="cov8" title="1">_ = fs.Parse(remaining) if *showVersion </span><span class="cov8" title="1">{ fmt.Fprintln(os.Stdout, internal.Version) return }</span> - - <span class="cov0" title="0">if err := hexaicli.Run(context.Background(), flag.Args(), os.Stdin, os.Stdout, os.Stderr); err != nil </span><span class="cov0" title="0">{ + <span class="cov0" title="0">var selection []int + for i, sel := range selectedFlags </span><span class="cov0" title="0">{ + if sel </span><span class="cov0" title="0">{ + selection = append(selection, i) + }</span> + } + <span class="cov0" title="0">finalPath := strings.TrimSpace(*configFlag) + if finalPath == "" </span><span class="cov0" title="0">{ + finalPath = configPath + }</span> + <span class="cov0" title="0">ctx := context.Background() + if finalPath != "" </span><span class="cov0" title="0">{ + ctx = hexaicli.WithCLIConfigPath(ctx, finalPath) + }</span> + <span class="cov0" title="0">if len(selection) > 0 </span><span class="cov0" title="0">{ + ctx = hexaicli.WithCLISelection(ctx, selection) + }</span> + <span class="cov0" title="0">if err := hexaicli.Run(ctx, fs.Args(), os.Stdin, os.Stdout, os.Stderr); err != nil </span><span class="cov0" title="0">{ os.Exit(1) }</span> } + +func splitConfigPath(args []string) (string, []string) <span class="cov8" title="1">{ + var path string + rest := make([]string, 0, len(args)) + skip := false + for i := 0; i < len(args); i++ </span><span class="cov8" title="1">{ + if skip </span><span class="cov0" title="0">{ + skip = false + continue</span> + } + <span class="cov8" title="1">arg := args[i] + switch </span>{ + case arg == "--config" || arg == "-config":<span class="cov0" title="0"> + if i+1 < len(args) </span><span class="cov0" title="0">{ + path = args[i+1] + skip = true + }</span> + case strings.HasPrefix(arg, "--config="):<span class="cov0" title="0"> + path = arg[len("--config="):]</span> + case strings.HasPrefix(arg, "-config="):<span class="cov0" title="0"> + path = arg[len("-config="):]</span> + default:<span class="cov8" title="1"> + rest = append(rest, arg)</span> + } + } + <span class="cov8" title="1">return strings.TrimSpace(path), rest</span> +} + +func pickDefaultModel(cfg appconfig.App, provider string) string <span class="cov8" title="1">{ + switch strings.ToLower(strings.TrimSpace(provider)) </span>{ + case "ollama":<span class="cov0" title="0"> + return strings.TrimSpace(cfg.OllamaModel)</span> + case "copilot":<span class="cov0" title="0"> + return strings.TrimSpace(cfg.CopilotModel)</span> + default:<span class="cov8" title="1"> + return strings.TrimSpace(cfg.OpenAIModel)</span> + } +} + +func defaultConfigPath() string <span class="cov8" title="1">{ + cfgPath, err := appconfig.ConfigPath() + if err != nil </span><span class="cov0" title="0">{ + return "$XDG_CONFIG_HOME/hexai/config.toml" + }</span> + <span class="cov8" title="1">return cfgPath</span> +} </pre> <pre class="file" id="file3" style="display: none">// Summary: Application configuration model and loader; reads ~/.config/hexai/config.toml and merges defaults. @@ -260,6 +383,13 @@ import ( "github.com/pelletier/go-toml/v2" ) +// SurfaceConfig describes a provider/model pairing (with optional temperature). +type SurfaceConfig struct { + Provider string + Model string + Temperature *float64 +} + // App holds user-configurable settings read from ~/.config/hexai/config.toml. type App struct { MaxTokens int `json:"max_tokens" toml:"max_tokens"` @@ -284,7 +414,7 @@ type App struct { TriggerCharacters []string `json:"trigger_characters" toml:"trigger_characters"` Provider string `json:"provider" toml:"provider"` - // Inline prompt trigger characters (default: >text> and >>text>) + // Inline prompt trigger characters (default: >!text> and >>!text>) InlineOpen string `json:"inline_open" toml:"inline_open"` InlineClose string `json:"inline_close" toml:"inline_close"` // In-editor chat triggers (default: suffix ">" after one of [?, !, :, ;]) @@ -296,8 +426,12 @@ type App struct { OpenAIModel string `json:"openai_model" toml:"openai_model"` // Default temperature for OpenAI requests (nil means use provider default) OpenAITemperature *float64 `json:"openai_temperature" toml:"openai_temperature"` - OllamaBaseURL string `json:"ollama_base_url" toml:"ollama_base_url"` - OllamaModel string `json:"ollama_model" toml:"ollama_model"` + OpenRouterBaseURL string `json:"openrouter_base_url" toml:"openrouter_base_url"` + OpenRouterModel string `json:"openrouter_model" toml:"openrouter_model"` + // Default temperature for OpenRouter requests (nil means use provider default) + OpenRouterTemperature *float64 `json:"openrouter_temperature" toml:"openrouter_temperature"` + OllamaBaseURL string `json:"ollama_base_url" toml:"ollama_base_url"` + OllamaModel string `json:"ollama_model" toml:"ollama_model"` // Default temperature for Ollama requests (nil means use provider default) OllamaTemperature *float64 `json:"ollama_temperature" toml:"ollama_temperature"` CopilotBaseURL string `json:"copilot_base_url" toml:"copilot_base_url"` @@ -305,6 +439,12 @@ type App struct { // Default temperature for Copilot requests (nil means use provider default) CopilotTemperature *float64 `json:"copilot_temperature" toml:"copilot_temperature"` + // Per-surface provider/model configurations (ordered; first entry is primary) + CompletionConfigs []SurfaceConfig `json:"-" toml:"-"` + CodeActionConfigs []SurfaceConfig `json:"-" toml:"-"` + ChatConfigs []SurfaceConfig `json:"-" toml:"-"` + CLIConfigs []SurfaceConfig `json:"-" toml:"-"` + // Prompt templates (configured only via file; no env overrides) // Completion/chat/code action/CLI prompt strings. See config.toml.example for placeholders. // Completion @@ -353,7 +493,7 @@ type CustomAction struct { } // Constructor: defaults for App (kept first among functions) -func newDefaultConfig() App <span class="cov6" title="49">{ +func newDefaultConfig() App <span class="cov5" title="51">{ // Coding-friendly default temperature across providers // Users can override per provider in config.toml (including 0.0). t := 0.2 @@ -371,7 +511,7 @@ func newDefaultConfig() App <span class="cov6" title="49">{ CompletionDebounceMs: 800, CompletionThrottleMs: 0, // Inline/chat trigger defaults - InlineOpen: ">", + InlineOpen: ">!", InlineClose: ">", ChatSuffix: ">", ChatPrefixes: []string{"?", "!", ":", ";"}, @@ -409,40 +549,45 @@ func newDefaultConfig() App <span class="cov6" title="49">{ // Load reads configuration from a file and merges with defaults. // It respects the XDG Base Directory Specification. -func Load(logger *log.Logger) App <span class="cov6" title="44">{ return LoadWithOptions(logger, LoadOptions{}) }</span> +func Load(logger *log.Logger) App <span class="cov5" title="35">{ return LoadWithOptions(logger, LoadOptions{}) }</span> // LoadOptions tune how configuration is loaded at runtime. type LoadOptions struct { // IgnoreEnv skips applying environment overrides when true. - IgnoreEnv bool + IgnoreEnv bool + ConfigPath string } // LoadWithOptions reads configuration and applies the requested loading options. -func LoadWithOptions(logger *log.Logger, opts LoadOptions) App <span class="cov6" title="48">{ +func LoadWithOptions(logger *log.Logger, opts LoadOptions) App <span class="cov5" title="50">{ cfg := newDefaultConfig() if logger == nil </span><span class="cov4" title="13">{ return cfg // Return defaults if no logger is provided (e.g. in tests) }</span> - <span class="cov5" title="35">configPath, err := getConfigPath() - if err != nil </span><span class="cov0" title="0">{ - logger.Printf("%v", err) - // Even if config path cannot be resolved, keep defaults and optionally apply env overrides below. - }</span> else<span class="cov5" title="35"> { - if fileCfg, err := loadFromFile(configPath, logger); err == nil && fileCfg != nil </span><span class="cov5" title="30">{ + <span class="cov5" title="37">configPath := strings.TrimSpace(opts.ConfigPath) + if configPath != "" </span><span class="cov0" title="0">{ + if fileCfg, err := loadFromFile(configPath, logger); err == nil && fileCfg != nil </span><span class="cov0" title="0">{ + cfg.mergeWith(fileCfg) + }</span> else<span class="cov0" title="0"> if err != nil </span><span class="cov0" title="0">{ + logger.Printf("cannot open config file %s: %v", configPath, err) + }</span> + } else<span class="cov5" title="37"> { + path, err := getConfigPath() + if err != nil </span><span class="cov0" title="0">{ + logger.Printf("%v", err) + }</span> else<span class="cov5" title="37"> if fileCfg, err := loadFromFile(path, logger); err == nil && fileCfg != nil </span><span class="cov4" title="21">{ cfg.mergeWith(fileCfg) }</span> - // When the config file is missing or invalid, we keep defaults and still - // apply any environment overrides below (unless disabled). } - <span class="cov5" title="35">if !opts.IgnoreEnv </span><span class="cov5" title="31">{ + <span class="cov5" title="37">if !opts.IgnoreEnv </span><span class="cov5" title="33">{ // Environment overrides (take precedence over file) - if envCfg := loadFromEnv(logger); envCfg != nil </span><span class="cov3" title="8">{ + if envCfg := loadFromEnv(logger); envCfg != nil </span><span class="cov3" title="9">{ cfg.mergeWith(envCfg) }</span> } - <span class="cov5" title="35">return cfg</span> + <span class="cov5" title="37">return cfg</span> } // Private helpers @@ -457,6 +602,7 @@ type fileConfig struct { Chat sectionChat `toml:"chat"` Provider sectionProvider `toml:"provider"` OpenAI sectionOpenAI `toml:"openai"` + OpenRouter sectionOpenRouter `toml:"openrouter"` Copilot sectionCopilot `toml:"copilot"` Ollama sectionOllama `toml:"ollama"` Prompts sectionPrompts `toml:"prompts"` @@ -511,16 +657,16 @@ type sectionOpenAI struct { Presets map[string]string `toml:"presets"` } -func (s sectionOpenAI) isZero() bool <span class="cov5" title="30">{ +func (s sectionOpenAI) isZero() bool <span class="cov4" title="23">{ return strings.TrimSpace(s.Model) == "" && strings.TrimSpace(s.BaseURL) == "" && s.Temperature == nil && len(s.Presets) == 0 }</span> -func (s sectionOpenAI) resolvedModel() string <span class="cov4" title="14">{ +func (s sectionOpenAI) resolvedModel() string <span class="cov3" title="6">{ model := strings.TrimSpace(s.Model) if model == "" </span><span class="cov0" title="0">{ return "" }</span> - <span class="cov4" title="14">if len(s.Presets) == 0 </span><span class="cov4" title="13">{ + <span class="cov3" title="6">if len(s.Presets) == 0 </span><span class="cov3" title="5">{ return model }</span> <span class="cov1" title="1">if mapped := strings.TrimSpace(s.Presets[model]); mapped != "" </span><span class="cov1" title="1">{ @@ -537,6 +683,12 @@ func (s sectionOpenAI) resolvedModel() string <span class="cov4" title="14">{ <span class="cov0" title="0">return model</span> } +type sectionOpenRouter struct { + Model string `toml:"model"` + BaseURL string `toml:"base_url"` + Temperature *float64 `toml:"temperature"` +} + type sectionCopilot struct { Model string `toml:"model"` BaseURL string `toml:"base_url"` @@ -609,11 +761,11 @@ type sectionTmux struct { CustomMenuHotkey string `toml:"custom_menu_hotkey"` } -func (fc *fileConfig) toApp() App <span class="cov5" title="30">{ +func (fc *fileConfig) toApp() App <span class="cov4" title="23">{ out := App{} // Merge section: general - if (fc.General != sectionGeneral{}) || fc.General.CodingTemperature != nil </span><span class="cov4" title="11">{ + if (fc.General != sectionGeneral{}) || fc.General.CodingTemperature != nil </span><span class="cov4" title="12">{ tmp := App{ MaxTokens: fc.General.MaxTokens, ContextMode: fc.General.ContextMode, @@ -625,13 +777,13 @@ func (fc *fileConfig) toApp() App <span class="cov5" title="30">{ }</span> // logging - <span class="cov5" title="30">if (fc.Logging != sectionLogging{}) </span><span class="cov1" title="1">{ + <span class="cov4" title="23">if (fc.Logging != sectionLogging{}) </span><span class="cov1" title="1">{ tmp := App{LogPreviewLimit: fc.Logging.LogPreviewLimit} out.mergeBasics(&tmp) }</span> // completion - <span class="cov5" title="30">if (fc.Completion != sectionCompletion{}) </span><span class="cov2" title="3">{ + <span class="cov4" title="23">if (fc.Completion != sectionCompletion{}) </span><span class="cov2" title="4">{ tmp := App{ CompletionDebounceMs: fc.Completion.CompletionDebounceMs, CompletionThrottleMs: fc.Completion.CompletionThrottleMs, @@ -641,31 +793,31 @@ func (fc *fileConfig) toApp() App <span class="cov5" title="30">{ }</span> // triggers - <span class="cov5" title="30">if len(fc.Triggers.TriggerCharacters) > 0 </span><span class="cov2" title="3">{ + <span class="cov4" title="23">if len(fc.Triggers.TriggerCharacters) > 0 </span><span class="cov2" title="4">{ tmp := App{TriggerCharacters: fc.Triggers.TriggerCharacters} out.mergeBasics(&tmp) }</span> // inline - <span class="cov5" title="30">if (fc.Inline != sectionInline{}) </span><span class="cov4" title="11">{ + <span class="cov4" title="23">if (fc.Inline != sectionInline{}) </span><span class="cov1" title="1">{ tmp := App{InlineOpen: fc.Inline.InlineOpen, InlineClose: fc.Inline.InlineClose} out.mergeBasics(&tmp) }</span> // chat - <span class="cov5" title="30">if strings.TrimSpace(fc.Chat.ChatSuffix) != "" || len(fc.Chat.ChatPrefixes) > 0 </span><span class="cov1" title="1">{ + <span class="cov4" title="23">if strings.TrimSpace(fc.Chat.ChatSuffix) != "" || len(fc.Chat.ChatPrefixes) > 0 </span><span class="cov1" title="1">{ tmp := App{ChatSuffix: fc.Chat.ChatSuffix, ChatPrefixes: fc.Chat.ChatPrefixes} out.mergeBasics(&tmp) }</span> // provider - <span class="cov5" title="30">if strings.TrimSpace(fc.Provider.Name) != "" </span><span class="cov2" title="4">{ + <span class="cov4" title="23">if strings.TrimSpace(fc.Provider.Name) != "" </span><span class="cov3" title="6">{ tmp := App{Provider: fc.Provider.Name} out.mergeBasics(&tmp) }</span> // openai - <span class="cov5" title="30">if !fc.OpenAI.isZero() || fc.OpenAI.Temperature != nil </span><span class="cov4" title="14">{ + <span class="cov4" title="23">if !fc.OpenAI.isZero() || fc.OpenAI.Temperature != nil </span><span class="cov3" title="6">{ tmp := App{ OpenAIBaseURL: fc.OpenAI.BaseURL, OpenAIModel: fc.OpenAI.resolvedModel(), @@ -674,8 +826,18 @@ func (fc *fileConfig) toApp() App <span class="cov5" title="30">{ out.mergeProviderFields(&tmp) }</span> + // openrouter + <span class="cov4" title="23">if (fc.OpenRouter != sectionOpenRouter{}) || fc.OpenRouter.Temperature != nil </span><span class="cov0" title="0">{ + tmp := App{ + OpenRouterBaseURL: fc.OpenRouter.BaseURL, + OpenRouterModel: fc.OpenRouter.Model, + OpenRouterTemperature: fc.OpenRouter.Temperature, + } + out.mergeProviderFields(&tmp) + }</span> + // copilot - <span class="cov5" title="30">if (fc.Copilot != sectionCopilot{}) || fc.Copilot.Temperature != nil </span><span class="cov2" title="3">{ + <span class="cov4" title="23">if (fc.Copilot != sectionCopilot{}) || fc.Copilot.Temperature != nil </span><span class="cov2" title="4">{ tmp := App{ CopilotBaseURL: fc.Copilot.BaseURL, CopilotModel: fc.Copilot.Model, @@ -685,7 +847,7 @@ func (fc *fileConfig) toApp() App <span class="cov5" title="30">{ }</span> // ollama - <span class="cov5" title="30">if (fc.Ollama != sectionOllama{}) || fc.Ollama.Temperature != nil </span><span class="cov2" title="3">{ + <span class="cov4" title="23">if (fc.Ollama != sectionOllama{}) || fc.Ollama.Temperature != nil </span><span class="cov2" title="4">{ tmp := App{ OllamaBaseURL: fc.Ollama.BaseURL, OllamaModel: fc.Ollama.Model, @@ -696,7 +858,7 @@ func (fc *fileConfig) toApp() App <span class="cov5" title="30">{ // prompts // completion - <span class="cov5" title="30">if (fc.Prompts.Completion != sectionPromptsCompletion{}) </span><span class="cov1" title="1">{ + <span class="cov4" title="23">if (fc.Prompts.Completion != sectionPromptsCompletion{}) </span><span class="cov1" title="1">{ if strings.TrimSpace(fc.Prompts.Completion.SystemGeneral) != "" </span><span class="cov1" title="1">{ out.PromptCompletionSystemGeneral = fc.Prompts.Completion.SystemGeneral }</span> @@ -717,11 +879,11 @@ func (fc *fileConfig) toApp() App <span class="cov5" title="30">{ }</span> } // chat - <span class="cov5" title="30">if strings.TrimSpace(fc.Prompts.Chat.System) != "" </span><span class="cov1" title="1">{ + <span class="cov4" title="23">if strings.TrimSpace(fc.Prompts.Chat.System) != "" </span><span class="cov1" title="1">{ out.PromptChatSystem = fc.Prompts.Chat.System }</span> // code action - <span class="cov5" title="30">if strings.TrimSpace(fc.Prompts.CodeAction.RewriteSystem) != "" || + <span class="cov4" title="23">if strings.TrimSpace(fc.Prompts.CodeAction.RewriteSystem) != "" || strings.TrimSpace(fc.Prompts.CodeAction.DiagnosticsSystem) != "" || strings.TrimSpace(fc.Prompts.CodeAction.DocumentSystem) != "" || strings.TrimSpace(fc.Prompts.CodeAction.RewriteUser) != "" || @@ -731,39 +893,39 @@ func (fc *fileConfig) toApp() App <span class="cov5" title="30">{ strings.TrimSpace(fc.Prompts.CodeAction.GoTestUser) != "" || strings.TrimSpace(fc.Prompts.CodeAction.SimplifySystem) != "" || strings.TrimSpace(fc.Prompts.CodeAction.SimplifyUser) != "" || - len(fc.Prompts.CodeAction.Custom) > 0 </span><span class="cov4" title="17">{ + len(fc.Prompts.CodeAction.Custom) > 0 </span><span class="cov3" title="7">{ if strings.TrimSpace(fc.Prompts.CodeAction.RewriteSystem) != "" </span><span class="cov1" title="1">{ out.PromptCodeActionRewriteSystem = fc.Prompts.CodeAction.RewriteSystem }</span> - <span class="cov4" title="17">if strings.TrimSpace(fc.Prompts.CodeAction.DiagnosticsSystem) != "" </span><span class="cov1" title="1">{ + <span class="cov3" title="7">if strings.TrimSpace(fc.Prompts.CodeAction.DiagnosticsSystem) != "" </span><span class="cov1" title="1">{ out.PromptCodeActionDiagnosticsSystem = fc.Prompts.CodeAction.DiagnosticsSystem }</span> - <span class="cov4" title="17">if strings.TrimSpace(fc.Prompts.CodeAction.DocumentSystem) != "" </span><span class="cov1" title="1">{ + <span class="cov3" title="7">if strings.TrimSpace(fc.Prompts.CodeAction.DocumentSystem) != "" </span><span class="cov1" title="1">{ out.PromptCodeActionDocumentSystem = fc.Prompts.CodeAction.DocumentSystem }</span> - <span class="cov4" title="17">if strings.TrimSpace(fc.Prompts.CodeAction.RewriteUser) != "" </span><span class="cov1" title="1">{ + <span class="cov3" title="7">if strings.TrimSpace(fc.Prompts.CodeAction.RewriteUser) != "" </span><span class="cov1" title="1">{ out.PromptCodeActionRewriteUser = fc.Prompts.CodeAction.RewriteUser }</span> - <span class="cov4" title="17">if strings.TrimSpace(fc.Prompts.CodeAction.DiagnosticsUser) != "" </span><span class="cov1" title="1">{ + <span class="cov3" title="7">if strings.TrimSpace(fc.Prompts.CodeAction.DiagnosticsUser) != "" </span><span class="cov1" title="1">{ out.PromptCodeActionDiagnosticsUser = fc.Prompts.CodeAction.DiagnosticsUser }</span> - <span class="cov4" title="17">if strings.TrimSpace(fc.Prompts.CodeAction.DocumentUser) != "" </span><span class="cov1" title="1">{ + <span class="cov3" title="7">if strings.TrimSpace(fc.Prompts.CodeAction.DocumentUser) != "" </span><span class="cov1" title="1">{ out.PromptCodeActionDocumentUser = fc.Prompts.CodeAction.DocumentUser }</span> - <span class="cov4" title="17">if strings.TrimSpace(fc.Prompts.CodeAction.GoTestSystem) != "" </span><span class="cov1" title="1">{ + <span class="cov3" title="7">if strings.TrimSpace(fc.Prompts.CodeAction.GoTestSystem) != "" </span><span class="cov1" title="1">{ out.PromptCodeActionGoTestSystem = fc.Prompts.CodeAction.GoTestSystem }</span> - <span class="cov4" title="17">if strings.TrimSpace(fc.Prompts.CodeAction.GoTestUser) != "" </span><span class="cov1" title="1">{ + <span class="cov3" title="7">if strings.TrimSpace(fc.Prompts.CodeAction.GoTestUser) != "" </span><span class="cov1" title="1">{ out.PromptCodeActionGoTestUser = fc.Prompts.CodeAction.GoTestUser }</span> - <span class="cov4" title="17">if strings.TrimSpace(fc.Prompts.CodeAction.SimplifySystem) != "" </span><span class="cov0" title="0">{ + <span class="cov3" title="7">if strings.TrimSpace(fc.Prompts.CodeAction.SimplifySystem) != "" </span><span class="cov0" title="0">{ out.PromptCodeActionSimplifySystem = fc.Prompts.CodeAction.SimplifySystem }</span> - <span class="cov4" title="17">if strings.TrimSpace(fc.Prompts.CodeAction.SimplifyUser) != "" </span><span class="cov0" title="0">{ + <span class="cov3" title="7">if strings.TrimSpace(fc.Prompts.CodeAction.SimplifyUser) != "" </span><span class="cov0" title="0">{ out.PromptCodeActionSimplifyUser = fc.Prompts.CodeAction.SimplifyUser }</span> - <span class="cov4" title="17">if len(fc.Prompts.CodeAction.Custom) > 0 </span><span class="cov4" title="16">{ - for _, ca := range fc.Prompts.CodeAction.Custom </span><span class="cov5" title="30">{ + <span class="cov3" title="7">if len(fc.Prompts.CodeAction.Custom) > 0 </span><span class="cov3" title="6">{ + for _, ca := range fc.Prompts.CodeAction.Custom </span><span class="cov3" title="10">{ out.CustomActions = append(out.CustomActions, CustomAction{ ID: strings.TrimSpace(ca.ID), Title: strings.TrimSpace(ca.Title), @@ -778,7 +940,7 @@ func (fc *fileConfig) toApp() App <span class="cov5" title="30">{ } } // cli - <span class="cov5" title="30">if (fc.Prompts.CLI != sectionPromptsCLI{}) </span><span class="cov1" title="1">{ + <span class="cov4" title="23">if (fc.Prompts.CLI != sectionPromptsCLI{}) </span><span class="cov1" title="1">{ if strings.TrimSpace(fc.Prompts.CLI.DefaultSystem) != "" </span><span class="cov1" title="1">{ out.PromptCLIDefaultSystem = fc.Prompts.CLI.DefaultSystem }</span> @@ -787,46 +949,46 @@ func (fc *fileConfig) toApp() App <span class="cov5" ti |
