diff options
30 files changed, 28903 insertions, 34758 deletions
@@ -36,7 +36,6 @@ export HEXAI_REQUEST_TIMEOUT=120 - `internal/llm/openai.go` - Added `newOpenAIWithTimeout` - `internal/llm/ollama.go` - Added `newOllamaWithTimeout` - `internal/llm/openrouter.go` - Added `newOpenRouterWithTimeout` -- `internal/llm/copilot.go` - Added `newCopilotWithTimeout` - `internal/llm/anthropic.go` - Added `newAnthropicWithTimeout` - `internal/hexailsp/run.go` - Pass `RequestTimeout` to `llm.Config` - `internal/llmutils/client.go` - Pass `RequestTimeout` to `llm.Config` @@ -15,7 +15,7 @@ It has got improved capabilities for Go code understanding (for example, create * Parallel completions and CLI responses from multiple providers/models for side-by-side comparison * TUI AI code-action runner (`hexai-tmux-action`) with Bubble Tea - Includes a “Custom prompt” action (hotkey `p`) that opens your editor (`$HEXAI_EDITOR` or `$EDITOR`) on a temporary Markdown file. -* Support for OpenAI, OpenRouter, GitHub Copilot, Anthropic, and Ollama +* Support for OpenAI, OpenRouter, Anthropic, and Ollama ## Documentation diff --git a/cmd/hexai/main.go b/cmd/hexai/main.go index 7caedc6..15fda42 100644 --- a/cmd/hexai/main.go +++ b/cmd/hexai/main.go @@ -100,8 +100,8 @@ func pickDefaultModel(cfg appconfig.App, provider string) string { switch strings.ToLower(strings.TrimSpace(provider)) { case "ollama": return strings.TrimSpace(cfg.OllamaModel) - case "copilot": - return strings.TrimSpace(cfg.CopilotModel) + case "anthropic": + return strings.TrimSpace(cfg.AnthropicModel) default: return strings.TrimSpace(cfg.OpenAIModel) } diff --git a/config.toml.example b/config.toml.example index cc34e04..bb8165d 100644 --- a/config.toml.example +++ b/config.toml.example @@ -52,8 +52,8 @@ chat_prefixes = ["?", "!", ":", ";"] # single-character items # [[models.code_action]] # # Only the first entry is used; extras are ignored with a warning. -# provider = "copilot" -# model = "gpt-4o" +# provider = "anthropic" +# model = "claude-3-5-sonnet" # temperature = 0.4 # [[models.cli]] @@ -62,7 +62,7 @@ chat_prefixes = ["?", "!", ":", ";"] # single-character items # temperature = 0.6 [provider] -name = "openai" # openai | openrouter | copilot | ollama | anthropic +name = "openai" # openai | openrouter | anthropic | ollama [openai] model = "gpt-4.1" @@ -74,11 +74,6 @@ model = "openrouter/auto" base_url = "https://openrouter.ai/api/v1" temperature = 0.2 -[copilot] -model = "gpt-4o-mini" -base_url = "https://api.githubcopilot.com" -temperature = 0.2 - [ollama] model = "qwen3-coder:30b-a3b-q4_K_M" base_url = "http://localhost:11434" diff --git a/docs/configuration.md b/docs/configuration.md index 54ac85f..f4469a9 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -20,7 +20,6 @@ Environment overrides - `HEXAI_CHAT_SUFFIX`, `HEXAI_CHAT_PREFIXES` (comma-separated) - `HEXAI_OPENAI_MODEL`, `HEXAI_OPENAI_BASE_URL`, `HEXAI_OPENAI_TEMPERATURE` - `HEXAI_OPENROUTER_MODEL`, `HEXAI_OPENROUTER_BASE_URL`, `HEXAI_OPENROUTER_TEMPERATURE` - - `HEXAI_COPILOT_MODEL`, `HEXAI_COPILOT_BASE_URL`, `HEXAI_COPILOT_TEMPERATURE` - `HEXAI_OLLAMA_MODEL`, `HEXAI_OLLAMA_BASE_URL`, `HEXAI_OLLAMA_TEMPERATURE` - Per-surface overrides: `HEXAI_MODEL_COMPLETION`, `HEXAI_MODEL_CODE_ACTION`, `HEXAI_MODEL_CHAT`, `HEXAI_MODEL_CLI` - Per-surface temperatures: `HEXAI_TEMPERATURE_COMPLETION`, `HEXAI_TEMPERATURE_CODE_ACTION`, `HEXAI_TEMPERATURE_CHAT`, `HEXAI_TEMPERATURE_CLI` @@ -37,7 +36,7 @@ Per-surface models [models.code_action] model = "gpt-4o" - provider = "copilot" + provider = "openai" temperature = 0.4 [models.cli] @@ -47,7 +46,7 @@ Per-surface models - Repeating the table (`[[models.<surface>]]`) configures multiple provider/model pairs. Completion requests and the Hexai CLI fan out to every configured entry concurrently and label the responses with `provider:model`. Code actions continue to use the first entry only; any extra [[models.code_action]] tables are ignored at runtime and the loader logs a warning so you know an additional entry was skipped. -- When a per-surface value is omitted, Hexai falls back to the provider’s configured default. Temperatures inherit from `coding_temperature` unless explicitly set, and OpenAI `gpt-5*` models automatically raise an unspecified coding temperature to `1.0` for exploratory behavior. Provider overrides support `"openai"`, `"openrouter"`, `"copilot"`, or `"ollama"` and read the matching credential variables. +- When a per-surface value is omitted, Hexai falls back to the provider’s configured default. Temperatures inherit from `coding_temperature` unless explicitly set, and OpenAI `gpt-5*` models automatically raise an unspecified coding temperature to `1.0` for exploratory behavior. Provider overrides support `"openai"`, `"openrouter"`, `"anthropic"`, or `"ollama"` and read the matching credential variables. Runtime reloads @@ -61,11 +60,10 @@ API keys: - OpenAI: prefer `HEXAI_OPENAI_API_KEY`, falling back to `OPENAI_API_KEY`. - OpenRouter: prefer `HEXAI_OPENROUTER_API_KEY`, falling back to `OPENROUTER_API_KEY`. -- Copilot: prefer `HEXAI_COPILOT_API_KEY`, falling back to `COPILOT_API_KEY`. Selecting a provider -- Sectioned: set `[provider] name = "openai" | "openrouter" | "copilot" | "ollama"`. +- Sectioned: set `[provider] name = "openai" | "openrouter" | "anthropic" | "ollama"`. - If omitted, Hexai defaults to `openai`. - Selecting `openrouter` uses https://openrouter.ai/api/v1 by default and automatically sends the required `HTTP-Referer` (`https://github.com/snonux/hexai`) and `X-Title` (`Hexai`) headers. Override the base URL via `[openrouter]` or environment variables when needed. diff --git a/docs/coverage.html b/docs/coverage.html deleted file mode 100644 index 4526ad1..0000000 --- a/docs/coverage.html +++ /dev/null @@ -1,9825 +0,0 @@ - -<!DOCTYPE html> -<html> - <head> - <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> - <title>hexai-lsp: Go Coverage Report</title> - <style> - body { - background: black; - color: rgb(80, 80, 80); - } - body, pre, #legend span { - font-family: Menlo, monospace; - font-weight: bold; - } - #topbar { - background: black; - position: fixed; - top: 0; left: 0; right: 0; - height: 42px; - border-bottom: 1px solid rgb(80, 80, 80); - } - #content { - margin-top: 50px; - } - #nav, #legend { - float: left; - margin-left: 10px; - } - #legend { - margin-top: 12px; - } - #nav { - margin-top: 10px; - } - #legend span { - margin: 0 5px; - } - .cov0 { color: rgb(192, 0, 0) } -.cov1 { color: rgb(128, 128, 128) } -.cov2 { color: rgb(116, 140, 131) } -.cov3 { color: rgb(104, 152, 134) } -.cov4 { color: rgb(92, 164, 137) } -.cov5 { color: rgb(80, 176, 140) } -.cov6 { color: rgb(68, 188, 143) } -.cov7 { color: rgb(56, 200, 146) } -.cov8 { color: rgb(44, 212, 149) } -.cov9 { color: rgb(32, 224, 152) } -.cov10 { color: rgb(20, 236, 155) } - - </style> - </head> - <body> - <div id="topbar"> - <div id="nav"> - <select id="files"> - - <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 (61.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> - - <option value="file5">codeberg.org/snonux/hexai/internal/hexaiaction/cmdentry.go (84.5%)</option> - - <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.3%)</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> - - <option value="file10">codeberg.org/snonux/hexai/internal/hexaiaction/tui_custom.go (83.8%)</option> - - <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 (72.3%)</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 (87.1%)</option> - - <option value="file17">codeberg.org/snonux/hexai/internal/llm/openrouter.go (76.2%)</option> - - <option value="file18">codeberg.org/snonux/hexai/internal/llm/provider.go (86.0%)</option> - - <option value="file19">codeberg.org/snonux/hexai/internal/llm/util.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/chatlogger.go (100.0%)</option> - - <option value="file22">codeberg.org/snonux/hexai/internal/logging/logging.go (90.9%)</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/context.go (74.4%)</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.go (89.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_completion.go (79.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_execute.go (75.0%)</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/handlers_utils.go (85.3%)</option> - - <option value="file33">codeberg.org/snonux/hexai/internal/lsp/server.go (82.1%)</option> - - <option value="file34">codeberg.org/snonux/hexai/internal/lsp/transport.go (73.0%)</option> - - <option value="file35">codeberg.org/snonux/hexai/internal/runtimeconfig/store.go (88.1%)</option> - - <option value="file36">codeberg.org/snonux/hexai/internal/stats/lock_posix.go (83.3%)</option> - - <option value="file37">codeberg.org/snonux/hexai/internal/stats/stats.go (75.8%)</option> - - <option value="file38">codeberg.org/snonux/hexai/internal/testutil/fixtures.go (100.0%)</option> - - <option value="file39">codeberg.org/snonux/hexai/internal/textutil/human.go (92.3%)</option> - - <option value="file40">codeberg.org/snonux/hexai/internal/textutil/textutil.go (90.4%)</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> - <div id="legend"> - <span>not tracked</span> - - <span class="cov0">no coverage</span> - <span class="cov1">low coverage</span> - <span class="cov2">*</span> - <span class="cov3">*</span> - <span class="cov4">*</span> - <span class="cov5">*</span> - <span class="cov6">*</span> - <span class="cov7">*</span> - <span class="cov8">*</span> - <span class="cov9">*</span> - <span class="cov10">high coverage</span> - - </div> - </div> - <div id="content"> - - <pre class="file" id="file0" style="display: none">// Summary: Hexai LSP entrypoint; parses flags and delegates to internal/hexailsp. -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">{ - log.Println(internal.Version) - return - }</span> - - <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 - -import ( - "context" - "flag" - "fmt" - "os" - "strings" - - "codeberg.org/snonux/hexai/internal/appconfig" - "codeberg.org/snonux/hexai/internal/hexaiaction" -) - -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)") - flag.Parse() - - opts := hexaiaction.Options{ - Infile: *infile, Outfile: *outfile, - UIChild: *uiChild, TmuxTarget: *tmuxTarget, TmuxSplit: *tmuxSplit, TmuxPercent: *tmuxPercent, - } - 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. -package main - -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">{ - 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">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. -package appconfig - -import ( - "fmt" - "log" - "os" - "path/filepath" - "slices" - "strconv" - "strings" - - "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"` - ContextMode string `json:"context_mode" toml:"context_mode"` - ContextWindowLines int `json:"context_window_lines" toml:"context_window_lines"` - MaxContextTokens int `json:"max_context_tokens" toml:"max_context_tokens"` - LogPreviewLimit int `json:"log_preview_limit" toml:"log_preview_limit"` - // Single knob for LSP requests; if set, overrides hardcoded temps in LSP. - CodingTemperature *float64 `json:"coding_temperature" toml:"coding_temperature"` - // Minimum identifier characters required for manual (TriggerKind=1) invoke - // to proceed without structural triggers. 0 means always allow. - ManualInvokeMinPrefix int `json:"manual_invoke_min_prefix" toml:"manual_invoke_min_prefix"` - - // Completion debounce in milliseconds. When > 0, the server waits until - // there has been no text change for at least this duration before sending - // an LLM completion request. - CompletionDebounceMs int `json:"completion_debounce_ms" toml:"completion_debounce_ms"` - // Completion throttle in milliseconds. When > 0, caps the minimum spacing - // between LLM requests (both chat and code-completer paths). - CompletionThrottleMs int `json:"completion_throttle_ms" toml:"completion_throttle_ms"` - - TriggerCharacters []string `json:"trigger_characters" toml:"trigger_characters"` - Provider string `json:"provider" toml:"provider"` - - // 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 [?, !, :, ;]) - ChatSuffix string `json:"chat_suffix" toml:"chat_suffix"` - ChatPrefixes []string `json:"chat_prefixes" toml:"chat_prefixes"` - - // Provider-specific options - OpenAIBaseURL string `json:"openai_base_url" toml:"openai_base_url"` - 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"` - 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"` - CopilotModel string `json:"copilot_model" toml:"copilot_model"` - // 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 - PromptCompletionSystemGeneral string `json:"-" toml:"-"` - PromptCompletionSystemParams string `json:"-" toml:"-"` - PromptCompletionSystemInline string `json:"-" toml:"-"` - PromptCompletionUserGeneral string `json:"-" toml:"-"` - PromptCompletionUserParams string `json:"-" toml:"-"` - PromptCompletionExtraHeader string `json:"-" toml:"-"` - // Provider-native code-completer - PromptNativeCompletion string `json:"-" toml:"-"` - // In-editor chat - PromptChatSystem string `json:"-" toml:"-"` - // Code actions - PromptCodeActionRewriteSystem string `json:"-" toml:"-"` - PromptCodeActionDiagnosticsSystem string `json:"-" toml:"-"` - PromptCodeActionDocumentSystem string `json:"-" toml:"-"` - PromptCodeActionRewriteUser string `json:"-" toml:"-"` - PromptCodeActionDiagnosticsUser string `json:"-" toml:"-"` - PromptCodeActionDocumentUser string `json:"-" toml:"-"` - PromptCodeActionGoTestSystem string `json:"-" toml:"-"` - PromptCodeActionGoTestUser string `json:"-" toml:"-"` - PromptCodeActionSimplifySystem string `json:"-" toml:"-"` - PromptCodeActionSimplifyUser string `json:"-" toml:"-"` - // CLI - PromptCLIDefaultSystem string `json:"-" toml:"-"` - PromptCLIExplainSystem string `json:"-" toml:"-"` - - // Custom code actions and tmux integration - CustomActions []CustomAction `json:"-" toml:"-"` - TmuxCustomMenuHotkey string `json:"-" toml:"-"` - // Stats - StatsWindowMinutes int `json:"-" toml:"-"` -} - -// CustomAction describes a user-defined code action. -type CustomAction struct { - ID string - Title string - Kind string // optional; default "refactor" - Scope string // "selection" (default) | "diagnostics" - Hotkey string // optional, used by tmux submenu - Instruction string // optional; if set and User is empty, use global rewrite templates - System string // optional; used only when User is set - User string // optional; if set, render with available vars -} - -// Constructor: defaults for App (kept first among functions) -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 - return App{ - MaxTokens: 4000, - ContextMode: "always-full", - ContextWindowLines: 120, - MaxContextTokens: 4000, - LogPreviewLimit: 100, - CodingTemperature: &t, - OpenAITemperature: &t, - OllamaTemperature: &t, - CopilotTemperature: &t, - ManualInvokeMinPrefix: 0, - CompletionDebounceMs: 800, - CompletionThrottleMs: 0, - // Inline/chat trigger defaults - InlineOpen: ">!", - InlineClose: ">", - ChatSuffix: ">", - ChatPrefixes: []string{"?", "!", ":", ";"}, - - // Default prompt templates (match current hard-coded strings) - PromptCompletionSystemParams: "You are a code completion engine for function signatures. Return only the parameter list contents (without parentheses), no braces, no prose. Prefer idiomatic names and types.", - PromptCompletionUserParams: "Cursor is inside the function parameter list. Suggest only the parameter list (no parentheses).\nFunction line: {{function}}\nCurrent line (cursor at {{char}}): {{current}}", - PromptCompletionSystemGeneral: "You are a terse code completion engine. Return only the code to insert, no surrounding prose or backticks. Only continue from the cursor; never repeat characters already present to the left of the cursor on the current line (e.g., if 'name :=' is already typed, only return the right-hand side expression).", - PromptCompletionUserGeneral: "Provide the next likely code to insert at the cursor.\nFile: {{file}}\nFunction/context: {{function}}\nAbove line: {{above}}\nCurrent line (cursor at character {{char}}): {{current}}\nBelow line: {{below}}\nOnly return the completion snippet.", - PromptCompletionSystemInline: "You are a precise code completion/refactoring engine. Output only the code to insert with no prose, no comments, and no backticks. Return raw code only.", - PromptCompletionExtraHeader: "Additional context:\n{{context}}", - - PromptNativeCompletion: "// Path: {{path}}\n{{before}}", - - PromptChatSystem: "You are a helpful coding assistant. Answer concisely and clearly.", - - PromptCodeActionRewriteSystem: "You are a precise code refactoring engine. Rewrite the given code strictly according to the instruction. Return only the updated code with no prose or backticks. Preserve formatting where reasonable.", - PromptCodeActionDiagnosticsSystem: "You are a precise code fixer. Resolve the given diagnostics by editing only the selected code. Return only the co |
