a431d1ec95
Add OpenAI-compatible providers, TUI, slash commands, and model switching. Add local file tools plus optional yolo shell execution. Document config, usage, and development workflow.
143 lines
4.0 KiB
Go
143 lines
4.0 KiB
Go
package session
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
"sort"
|
|
"strings"
|
|
|
|
"agentu/internal/agent"
|
|
"agentu/internal/config"
|
|
"agentu/internal/llm"
|
|
)
|
|
|
|
type Manager struct {
|
|
cfg *config.Config
|
|
agent *agent.Agent
|
|
httpClient *http.Client
|
|
providerName string
|
|
provider config.ProviderConfig
|
|
}
|
|
|
|
func NewManager(cfg *config.Config, assistant *agent.Agent, httpClient *http.Client) (*Manager, error) {
|
|
if httpClient == nil {
|
|
httpClient = http.DefaultClient
|
|
}
|
|
providerName := cfg.DefaultProviderName()
|
|
provider, ok := cfg.Providers[providerName]
|
|
if !ok {
|
|
return nil, fmt.Errorf("no provider is configured")
|
|
}
|
|
return &Manager{
|
|
cfg: cfg,
|
|
agent: assistant,
|
|
httpClient: httpClient,
|
|
providerName: providerName,
|
|
provider: provider,
|
|
}, nil
|
|
}
|
|
|
|
func (m *Manager) CurrentProvider() string {
|
|
return m.providerName
|
|
}
|
|
|
|
func (m *Manager) CurrentModel() string {
|
|
return m.provider.Model
|
|
}
|
|
|
|
func (m *Manager) CurrentThinking() string {
|
|
if !m.provider.ThinkingConfigured {
|
|
return "unset"
|
|
}
|
|
return m.provider.Thinking
|
|
}
|
|
|
|
func (m *Manager) Info() string {
|
|
var b strings.Builder
|
|
fmt.Fprintf(&b, "provider: %s\n", m.CurrentProvider())
|
|
fmt.Fprintf(&b, "model: %s\n", m.CurrentModel())
|
|
fmt.Fprintf(&b, "thinking: %s\n", m.CurrentThinking())
|
|
fmt.Fprintf(&b, "providers: %s\n", strings.Join(m.providerNames(), ", "))
|
|
if len(m.provider.Models) > 0 {
|
|
fmt.Fprintf(&b, "models: %s\n", strings.Join(m.provider.Models, ", "))
|
|
} else {
|
|
b.WriteString("models: any model name is accepted for this provider\n")
|
|
}
|
|
fmt.Fprintf(&b, "thinking levels: %s\n", strings.Join(config.ThinkingLevels(), ", "))
|
|
b.WriteString("usage: /model provider <name> | /model model <name> | /model thinking <level>")
|
|
return b.String()
|
|
}
|
|
|
|
func (m *Manager) SetProvider(name string) (string, error) {
|
|
provider, ok := m.cfg.Providers[name]
|
|
if !ok {
|
|
return "", fmt.Errorf("unknown provider %q; available: %s", name, strings.Join(m.providerNames(), ", "))
|
|
}
|
|
m.providerName = name
|
|
m.provider = provider
|
|
m.syncAgent(llm.NewOpenAICompatibleClient(provider.BaseURL, provider.APIKey, m.httpClient))
|
|
return "Switched provider.\n" + m.summary(), nil
|
|
}
|
|
|
|
func (m *Manager) SetModel(model string) (string, error) {
|
|
model = strings.TrimSpace(model)
|
|
if model == "" {
|
|
return "", fmt.Errorf("model is required")
|
|
}
|
|
if len(m.provider.Models) > 0 && !contains(m.provider.Models, model) {
|
|
return "", fmt.Errorf("model %q is not configured for provider %q; available: %s", model, m.providerName, strings.Join(m.provider.Models, ", "))
|
|
}
|
|
m.provider.Model = model
|
|
m.cfg.Providers[m.providerName] = m.provider
|
|
m.syncAgent(nil)
|
|
return "Switched model.\n" + m.summary(), nil
|
|
}
|
|
|
|
func (m *Manager) SetThinking(level string) (string, error) {
|
|
level = strings.ToLower(strings.TrimSpace(level))
|
|
if !config.IsThinkingLevel(level) {
|
|
return "", fmt.Errorf("thinking must be one of: %s", strings.Join(config.ThinkingLevels(), ", "))
|
|
}
|
|
m.provider.Thinking = level
|
|
m.provider.ThinkingConfigured = true
|
|
if m.provider.ThinkingParam == "" {
|
|
m.provider.ThinkingParam = "thinking"
|
|
}
|
|
m.cfg.Providers[m.providerName] = m.provider
|
|
m.syncAgent(nil)
|
|
return "Updated thinking.\n" + m.summary(), nil
|
|
}
|
|
|
|
func (m *Manager) summary() string {
|
|
return fmt.Sprintf("provider: %s\nmodel: %s\nthinking: %s", m.CurrentProvider(), m.CurrentModel(), m.CurrentThinking())
|
|
}
|
|
|
|
func (m *Manager) syncAgent(provider llm.Provider) {
|
|
m.agent.SetRuntime(agent.RuntimeOptions{
|
|
Provider: provider,
|
|
ProviderName: m.providerName,
|
|
Model: m.provider.Model,
|
|
Thinking: m.provider.Thinking,
|
|
ThinkingParam: m.provider.ThinkingParam,
|
|
ThinkingEnabled: m.provider.ThinkingConfigured,
|
|
})
|
|
}
|
|
|
|
func (m *Manager) providerNames() []string {
|
|
names := make([]string, 0, len(m.cfg.Providers))
|
|
for name := range m.cfg.Providers {
|
|
names = append(names, name)
|
|
}
|
|
sort.Strings(names)
|
|
return names
|
|
}
|
|
|
|
func contains(values []string, value string) bool {
|
|
for _, item := range values {
|
|
if item == value {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|