Files
ai-agent/internal/agents/task/agent.go
2026-03-20 07:07:38 +01:00

210 lines
5.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// task/agent.go Task-Agent: add/list/done/delete
package task
import (
"fmt"
"strings"
"time"
"my-brain-importer/internal/agents"
)
// Agent verwaltet Aufgaben über tasks.json.
type Agent struct {
store *Store
}
// New erstellt einen neuen Task-Agenten.
func New() *Agent {
return &Agent{store: NewStore()}
}
// Handle unterstützt: add, list, done, delete
func (a *Agent) Handle(req agents.Request) agents.Response {
switch req.Action {
case agents.ActionAdd:
return a.add(req)
case agents.ActionList:
return a.list()
case agents.ActionDone:
return a.done(req)
case agents.ActionDelete:
return a.del(req)
default:
return agents.Response{Text: "❌ Unbekannte Task-Aktion. Verfügbar: add, list, done, delete"}
}
}
// parseAddArgs parst Text, --due YYYY-MM-DD und --priority WERT aus den Args.
func parseAddArgs(args []string) (text, priority string, dueDate *time.Time) {
var textParts []string
for i := 0; i < len(args); i++ {
switch args[i] {
case "--due", "-d":
i++
if i < len(args) {
t, err := time.Parse("2006-01-02", args[i])
if err == nil {
dueDate = &t
}
}
case "--priority", "-p":
i++
if i < len(args) {
priority = strings.ToLower(args[i])
}
default:
textParts = append(textParts, args[i])
}
}
text = strings.Join(textParts, " ")
return
}
func (a *Agent) add(req agents.Request) agents.Response {
if len(req.Args) == 0 {
return agents.Response{Text: "❌ Kein Task-Text angegeben."}
}
text, priority, dueDate := parseAddArgs(req.Args)
if text == "" {
return agents.Response{Text: "❌ Kein Task-Text angegeben."}
}
t, err := a.store.Add(text, priority, dueDate)
if err != nil {
return agents.Response{Error: err, Text: fmt.Sprintf("❌ Fehler: %v", err)}
}
shortID := t.ID
if len(shortID) > 6 {
shortID = shortID[len(shortID)-6:]
}
var extras []string
if t.Priority != "" {
extras = append(extras, "Priorität: "+t.Priority)
}
if t.DueDate != nil {
extras = append(extras, "Fällig: "+t.DueDate.Format("02.01.2006"))
}
info := ""
if len(extras) > 0 {
info = " (" + strings.Join(extras, ", ") + ")"
}
return agents.Response{Text: fmt.Sprintf("✅ Task hinzugefügt: `%s`%s (ID: `%s`)", t.Text, info, shortID)}
}
func (a *Agent) list() agents.Response {
tasks, err := a.store.Load()
if err != nil {
return agents.Response{Error: err, Text: fmt.Sprintf("❌ Fehler: %v", err)}
}
if len(tasks) == 0 {
return agents.Response{Text: "📋 Keine Tasks vorhanden."}
}
today := time.Now().Truncate(24 * time.Hour)
tomorrow := today.Add(24 * time.Hour)
var sb strings.Builder
sb.WriteString("📋 **Task-Liste:**\n\n")
openCount := 0
for _, t := range tasks {
status := "⬜"
if t.Done {
status = "✅"
} else {
openCount++
}
shortID := t.ID
if len(shortID) > 6 {
shortID = shortID[len(shortID)-6:]
}
var meta []string
if t.Priority != "" {
switch t.Priority {
case "hoch":
meta = append(meta, "🔴 hoch")
case "mittel":
meta = append(meta, "🟡 mittel")
case "niedrig":
meta = append(meta, "🟢 niedrig")
default:
meta = append(meta, t.Priority)
}
}
if t.DueDate != nil && !t.Done {
due := t.DueDate.Truncate(24 * time.Hour)
switch {
case due.Before(today):
meta = append(meta, "⏰ **ÜBERFÄLLIG** "+t.DueDate.Format("02.01."))
case due.Equal(today):
meta = append(meta, "⏰ heute fällig")
case due.Equal(tomorrow):
meta = append(meta, "📅 morgen fällig")
default:
meta = append(meta, "📅 "+t.DueDate.Format("02.01.2006"))
}
}
line := fmt.Sprintf("%s `%s` %s", status, shortID, t.Text)
if len(meta) > 0 {
line += " · " + strings.Join(meta, " · ")
}
sb.WriteString(line + "\n")
}
fmt.Fprintf(&sb, "\n*%d offen, %d gesamt*", openCount, len(tasks))
return agents.Response{Text: sb.String()}
}
func (a *Agent) done(req agents.Request) agents.Response {
if len(req.Args) == 0 {
return agents.Response{Text: "❌ Keine Task-ID angegeben."}
}
id := req.Args[0]
tasks, err := a.store.Load()
if err != nil {
return agents.Response{Error: err, Text: fmt.Sprintf("❌ Fehler: %v", err)}
}
fullID := resolveID(tasks, id)
if fullID == "" {
return agents.Response{Text: fmt.Sprintf("❌ Task `%s` nicht gefunden.", id)}
}
if err := a.store.MarkDone(fullID); err != nil {
return agents.Response{Error: err, Text: fmt.Sprintf("❌ Fehler: %v", err)}
}
return agents.Response{Text: fmt.Sprintf("✅ Task `%s` als erledigt markiert.", id)}
}
func (a *Agent) del(req agents.Request) agents.Response {
if len(req.Args) == 0 {
return agents.Response{Text: "❌ Keine Task-ID angegeben."}
}
id := req.Args[0]
tasks, err := a.store.Load()
if err != nil {
return agents.Response{Error: err, Text: fmt.Sprintf("❌ Fehler: %v", err)}
}
fullID := resolveID(tasks, id)
if fullID == "" {
return agents.Response{Text: fmt.Sprintf("❌ Task `%s` nicht gefunden.", id)}
}
if err := a.store.Delete(fullID); err != nil {
return agents.Response{Error: err, Text: fmt.Sprintf("❌ Fehler: %v", err)}
}
return agents.Response{Text: fmt.Sprintf("🗑️ Task `%s` gelöscht.", id)}
}
// resolveID findet eine vollständige ID aus einer vollständigen oder kurzen (letzte 6 Zeichen).
func resolveID(tasks []Task, id string) string {
for _, t := range tasks {
if t.ID == id {
return t.ID
}
}
for _, t := range tasks {
if len(t.ID) >= 6 && t.ID[len(t.ID)-6:] == id {
return t.ID
}
}
return ""
}