summaryrefslogtreecommitdiff
path: root/internal/hexaiaction/prompts.go
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2025-09-08 09:50:38 +0300
committerPaul Buetow <paul@buetow.org>2025-09-08 09:50:38 +0300
commitcead3ebde8f3aee0ef8677158d37f4d04c6629dc (patch)
treeeadf4928c13e4f1fd782e8e0955116a24cef1d27 /internal/hexaiaction/prompts.go
parent29b0da31acf02816ee9e8f1d5a1b9a0ad5993593 (diff)
tmux: colored LLM status with provider + stats; add start heartbeat for LSP/CLI/TUI; theme support via HEXAI_TMUX_STATUS_THEME and HEXAI_TMUX_STATUS_FG/BG; docs: update tmux options and add Helix+tmux quickstart
Diffstat (limited to 'internal/hexaiaction/prompts.go')
-rw-r--r--internal/hexaiaction/prompts.go107
1 files changed, 73 insertions, 34 deletions
diff --git a/internal/hexaiaction/prompts.go b/internal/hexaiaction/prompts.go
index 3c33f8a..e9d7fc6 100644
--- a/internal/hexaiaction/prompts.go
+++ b/internal/hexaiaction/prompts.go
@@ -1,13 +1,14 @@
package hexaiaction
import (
- "context"
- "strings"
- "time"
+ "context"
+ "strings"
+ "time"
- "codeberg.org/snonux/hexai/internal/appconfig"
- "codeberg.org/snonux/hexai/internal/llm"
- "codeberg.org/snonux/hexai/internal/textutil"
+ "codeberg.org/snonux/hexai/internal/appconfig"
+ "codeberg.org/snonux/hexai/internal/llm"
+ "codeberg.org/snonux/hexai/internal/textutil"
+ "codeberg.org/snonux/hexai/internal/tmux"
)
// Render performs simple {{var}} replacement like LSP.
@@ -18,12 +19,22 @@ func StripFences(s string) string { return textutil.StripCodeFences(s) }
type chatDoer interface {
Chat(ctx context.Context, msgs []llm.Message, opts ...llm.RequestOption) (string, error)
+ DefaultModel() string
+}
+
+type providerNamer interface{ Name() string }
+
+func providerOf(c any) string {
+ if n, ok := c.(providerNamer); ok {
+ return n.Name()
+ }
+ return "llm"
}
func runRewrite(ctx context.Context, cfg appconfig.App, client chatDoer, instruction, selection string) (string, error) {
- sys := cfg.PromptCodeActionRewriteSystem
- user := Render(cfg.PromptCodeActionRewriteUser, map[string]string{"instruction": instruction, "selection": selection})
- return runOnceWithOpts(ctx, client, sys, user, reqOptsFrom(cfg))
+ sys := cfg.PromptCodeActionRewriteSystem
+ user := Render(cfg.PromptCodeActionRewriteUser, map[string]string{"instruction": instruction, "selection": selection})
+ return runOnceWithOpts(ctx, client, sys, user, reqOptsFrom(cfg))
}
func runDiagnostics(ctx context.Context, cfg appconfig.App, client chatDoer, diags []string, selection string) (string, error) {
@@ -39,52 +50,80 @@ func runDiagnostics(ctx context.Context, cfg appconfig.App, client chatDoer, dia
}
sys := cfg.PromptCodeActionDiagnosticsSystem
user := Render(cfg.PromptCodeActionDiagnosticsUser, map[string]string{"diagnostics": b.String(), "selection": selection})
- return runOnceWithOpts(ctx, client, sys, user, reqOptsFrom(cfg))
+ return runOnceWithOpts(ctx, client, sys, user, reqOptsFrom(cfg))
}
func runDocument(ctx context.Context, cfg appconfig.App, client chatDoer, selection string) (string, error) {
- sys := cfg.PromptCodeActionDocumentSystem
- user := Render(cfg.PromptCodeActionDocumentUser, map[string]string{"selection": selection})
- return runOnceWithOpts(ctx, client, sys, user, reqOptsFrom(cfg))
+ sys := cfg.PromptCodeActionDocumentSystem
+ user := Render(cfg.PromptCodeActionDocumentUser, map[string]string{"selection": selection})
+ return runOnceWithOpts(ctx, client, sys, user, reqOptsFrom(cfg))
}
func runSimplify(ctx context.Context, cfg appconfig.App, client chatDoer, selection string) (string, error) {
- sys := cfg.PromptCodeActionSimplifySystem
- user := Render(cfg.PromptCodeActionSimplifyUser, map[string]string{"selection": selection})
- return runOnceWithOpts(ctx, client, sys, user, reqOptsFrom(cfg))
+ sys := cfg.PromptCodeActionSimplifySystem
+ user := Render(cfg.PromptCodeActionSimplifyUser, map[string]string{"selection": selection})
+ return runOnceWithOpts(ctx, client, sys, user, reqOptsFrom(cfg))
}
func runGoTest(ctx context.Context, cfg appconfig.App, client chatDoer, funcCode string) (string, error) {
sys := cfg.PromptCodeActionGoTestSystem
user := Render(cfg.PromptCodeActionGoTestUser, map[string]string{"function": funcCode})
- return runOnceWithOpts(ctx, client, sys, user, reqOptsFrom(cfg))
+ return runOnceWithOpts(ctx, client, sys, user, reqOptsFrom(cfg))
}
func runOnce(ctx context.Context, client chatDoer, sys, user string) (string, error) {
- msgs := []llm.Message{{Role: "system", Content: sys}, {Role: "user", Content: user}}
- txt, err := client.Chat(ctx, msgs)
- if err != nil {
- return "", err
- }
- return strings.TrimSpace(StripFences(txt)), nil
+ msgs := []llm.Message{{Role: "system", Content: sys}, {Role: "user", Content: user}}
+ start := time.Now()
+ txt, err := client.Chat(ctx, msgs)
+ if err != nil {
+ return "", err
+ }
+ out := strings.TrimSpace(StripFences(txt))
+ // Update tmux heartbeat with simple one-request stats
+ sent := 0
+ for _, m := range msgs {
+ sent += len(m.Content)
+ }
+ recv := len(out)
+ mins := time.Since(start).Minutes()
+ if mins <= 0 {
+ mins = 0.001
+ }
+ rpm := float64(1) / mins
+ _ = tmux.SetStatus(tmux.FormatLLMStatsStatusColored(providerOf(client), client.DefaultModel(), 1, rpm, int64(sent), int64(recv)))
+ return out, nil
}
func runOnceWithOpts(ctx context.Context, client chatDoer, sys, user string, opts []llm.RequestOption) (string, error) {
- msgs := []llm.Message{{Role: "system", Content: sys}, {Role: "user", Content: user}}
- txt, err := client.Chat(ctx, msgs, opts...)
- if err != nil {
- return "", err
- }
- return strings.TrimSpace(StripFences(txt)), nil
+ msgs := []llm.Message{{Role: "system", Content: sys}, {Role: "user", Content: user}}
+ start := time.Now()
+ txt, err := client.Chat(ctx, msgs, opts...)
+ if err != nil {
+ return "", err
+ }
+ out := strings.TrimSpace(StripFences(txt))
+ // Update tmux heartbeat with simple one-request stats
+ sent := 0
+ for _, m := range msgs {
+ sent += len(m.Content)
+ }
+ recv := len(out)
+ mins := time.Since(start).Minutes()
+ if mins <= 0 {
+ mins = 0.001
+ }
+ rpm := float64(1) / mins
+ _ = tmux.SetStatus(tmux.FormatLLMStatsStatusColored(providerOf(client), client.DefaultModel(), 1, rpm, int64(sent), int64(recv)))
+ return out, nil
}
// reqOptsFrom builds LLM request options similar to LSP behavior.
func reqOptsFrom(cfg appconfig.App) []llm.RequestOption {
- opts := []llm.RequestOption{llm.WithMaxTokens(cfg.MaxTokens)}
- if cfg.CodingTemperature != nil {
- opts = append(opts, llm.WithTemperature(*cfg.CodingTemperature))
- }
- return opts
+ opts := []llm.RequestOption{llm.WithMaxTokens(cfg.MaxTokens)}
+ if cfg.CodingTemperature != nil {
+ opts = append(opts, llm.WithTemperature(*cfg.CodingTemperature))
+ }
+ return opts
}
// Timeout helpers to mirror LSP behavior.