diff options
| author | Paul Buetow <paul@buetow.org> | 2026-02-08 16:31:40 +0200 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-02-08 16:31:40 +0200 |
| commit | c802ba5803de1a53749bb5c4ecbc0159fceb385f (patch) | |
| tree | 02e612286f36bc6c65563bc33cf53639817d2db1 /internal/tmuxedit/config_agent.go | |
| parent | 887d7bc186db90c3903851b0f1db2d24df5d7a7b (diff) | |
refactor tmuxedit to Agent interface with cursor/claude/config implementations
Replace monolithic AgentConfig struct with an Agent interface backed by
baseAgent defaults and separate implementations for cursor (box-drawing
extraction, bulk backspace clearing) and claude (section-scoped extraction
with continuation lines, vim clearing). Simple agents (amp, aider) and
user-defined agents use configAgent with baseAgent defaults.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Diffstat (limited to 'internal/tmuxedit/config_agent.go')
| -rw-r--r-- | internal/tmuxedit/config_agent.go | 134 |
1 files changed, 134 insertions, 0 deletions
diff --git a/internal/tmuxedit/config_agent.go b/internal/tmuxedit/config_agent.go new file mode 100644 index 0000000..2773025 --- /dev/null +++ b/internal/tmuxedit/config_agent.go @@ -0,0 +1,134 @@ +package tmuxedit + +import ( + "strings" + + "codeberg.org/snonux/hexai/internal/appconfig" +) + +// configAgent uses baseAgent defaults for all operations. It serves +// user-defined agents from TOML config and simple built-ins (amp, aider) +// that don't need specialized extraction or clearing logic. +type configAgent struct{ baseAgent } + +// builtinAgents returns the default set of agent implementations. Order +// matters: agents with distinctive UI elements (box-drawing, etc.) are +// checked first to avoid false positives from model names like "Claude +// 4.5 Sonnet" appearing in other agents' panes. +func builtinAgents() []Agent { + return []Agent{ + newCursorAgent(), + newClaudeAgent(), + &configAgent{baseAgent{ + name: "amp", + displayName: "Amp", + detectPattern: `(?i)(amp|sourcegraph)`, + promptPat: `(?m)>\s*(.+)$`, + clearFirst: true, + clearKeys: "C-u", + newlineKeys: "S-Enter", + submitKeys: "Enter", + }}, + &configAgent{baseAgent{ + name: "aider", + displayName: "Aider", + detectPattern: `(?i)aider`, + promptPat: `(?m)>\s*(.+)$`, + clearFirst: true, + clearKeys: "C-u", + newlineKeys: "", + submitKeys: "Enter", + }}, + } +} + +// genericAgent returns a fallback agent with no detection or prompt extraction. +// The user gets a blank editor and text is sent verbatim. +func genericAgent() Agent { + return &configAgent{baseAgent{ + name: "generic", + displayName: "Generic", + newlineKeys: "", + submitKeys: "Enter", + }} +} + +// resolveAgents merges built-in agent defaults with user-provided overrides +// from config. Agents are matched by name (case-insensitive); user config +// wins field-by-field over builtins. The Configurable interface provides +// access to baseAgent fields for merging. +func resolveAgents(cfgAgents []appconfig.TmuxEditAgentCfg) []Agent { + agents := builtinAgents() + for _, ca := range cfgAgents { + merged := false + for i, a := range agents { + if !strings.EqualFold(a.Name(), ca.Name) { + continue + } + if c, ok := a.(Configurable); ok { + mergeAgentConfig(c.Base(), ca) + } + merged = true + _ = i // index not needed; we modify through the pointer + break + } + if !merged { + agents = append(agents, agentFromConfig(ca)) + } + } + return agents +} + +// mergeAgentConfig overrides fields in base with non-zero values from cfg. +// It modifies the baseAgent in place via pointer. +func mergeAgentConfig(base *baseAgent, cfg appconfig.TmuxEditAgentCfg) { + if s := strings.TrimSpace(cfg.DisplayName); s != "" { + base.displayName = s + } + if s := strings.TrimSpace(cfg.DetectPattern); s != "" { + base.detectPattern = s + } + if s := strings.TrimSpace(cfg.SectionPattern); s != "" { + base.sectionPat = s + } + if s := strings.TrimSpace(cfg.PromptPattern); s != "" { + base.promptPat = s + } + if len(cfg.StripPatterns) > 0 { + base.stripPatterns = cfg.StripPatterns + } + if cfg.ClearFirst != nil { + base.clearFirst = *cfg.ClearFirst + } + if s := strings.TrimSpace(cfg.ClearKeys); s != "" { + base.clearKeys = s + } + if s := strings.TrimSpace(cfg.NewlineKeys); s != "" { + base.newlineKeys = s + } + if s := strings.TrimSpace(cfg.SubmitKeys); s != "" { + base.submitKeys = s + } +} + +// agentFromConfig creates a new configAgent from a user config entry. +func agentFromConfig(cfg appconfig.TmuxEditAgentCfg) Agent { + b := baseAgent{ + name: strings.TrimSpace(cfg.Name), + displayName: strings.TrimSpace(cfg.DisplayName), + detectPattern: strings.TrimSpace(cfg.DetectPattern), + sectionPat: strings.TrimSpace(cfg.SectionPattern), + promptPat: strings.TrimSpace(cfg.PromptPattern), + stripPatterns: cfg.StripPatterns, + clearKeys: strings.TrimSpace(cfg.ClearKeys), + newlineKeys: strings.TrimSpace(cfg.NewlineKeys), + submitKeys: strings.TrimSpace(cfg.SubmitKeys), + } + if cfg.ClearFirst != nil { + b.clearFirst = *cfg.ClearFirst + } + if b.displayName == "" { + b.displayName = b.name + } + return &configAgent{b} +} |
