diff --git a/agent/loop.go b/agent/loop.go index ae851cd..2f94701 100644 --- a/agent/loop.go +++ b/agent/loop.go @@ -18,28 +18,20 @@ const ( maxTurns = 10 ) -var systemPrompt = `Du bist ein autonomer Coding-Agent. +var systemPrompt = `Du bist ein Coding-Agent. Erledige den gegebenen Task. -` + BuildToolPrompt() + ` - -WICHTIGE REGELN: -1. Nutze IMMER relative Pfade (z.B. hello.go, nicht /absoluter/pfad/hello.go) -2. Schreibe Dateiinhalt NIEMALS in Markdown-Codeblöcken (keine Backticks) -3. Nutze IMMER das <<<...>>> Format für WRITE_FILE -4. Wenn der Task erledigt ist, schreibe EXAKT auf einer eigenen Zeile: TASK_COMPLETE - -Beispiel: -TOOL:WRITE_FILE:hello.go +TOOLS: +TOOL:READ_FILE:pfad +TOOL:WRITE_FILE:pfad <<< -package main - -import "fmt" - -func main() { - fmt.Println("Hello World") -} +inhalt >>> -TASK_COMPLETE` +TOOL:LIST_FILES:pfad + +REGELN: +- Nutze relative Pfade +- Kein Markdown in Dateiinhalten +- Task erledigt: schreibe TASK_COMPLETE` type AgentLoop struct { client *openai.Client @@ -116,16 +108,29 @@ func (a *AgentLoop) runTask(task prd.Task) error { // Frischer Kontext pro Task messages := []openai.ChatCompletionMessageParamUnion{ openai.SystemMessage(systemPrompt), - openai.UserMessage(fmt.Sprintf("Task: %s\nArbeitsverzeichnis: %s", task.Title, a.workDir)), + openai.UserMessage(fmt.Sprintf( + "Task: %s\nArbeitsverzeichnis: %s", + task.Title, + a.workDir, + )), } - // System-Prompt und initialen User-Message loggen a.log.ChatMessage("system", systemPrompt) - a.log.ChatMessage("user", fmt.Sprintf("Task: %s\nArbeitsverzeichnis: %s", task.Title, a.workDir)) + a.log.ChatMessage("user", fmt.Sprintf( + "Task: %s\nArbeitsverzeichnis: %s", + task.Title, + a.workDir, + )) for turn := 0; turn < maxTurns; turn++ { a.log.Turn(turn + 1) + // Token-Schätzung für Debugging + totalChars := 0 + for _, m := range messages { + totalChars += len(fmt.Sprintf("%v", m)) + } + resp, err := a.client.Chat.Completions.New( context.Background(), openai.ChatCompletionNewParams{ @@ -134,7 +139,7 @@ func (a *AgentLoop) runTask(task prd.Task) error { }, ) if err != nil { - return fmt.Errorf("API-Fehler: %w", err) + return fmt.Errorf("API-Fehler (~%d Zeichen im Kontext): %w", totalChars, err) } response := resp.Choices[0].Message.Content @@ -142,7 +147,7 @@ func (a *AgentLoop) runTask(task prd.Task) error { messages = append(messages, openai.AssistantMessage(response)) // Completion Detection - if strings.Contains(response, "TASK_COMPLETE") { + if isTaskComplete(response) { return nil } @@ -155,10 +160,31 @@ func (a *AgentLoop) runTask(task prd.Task) error { } // Kein Tool, kein TASK_COMPLETE → anstupsen - nudge := "Bitte fahre fort. Wenn der Task erledigt ist, schreibe TASK_COMPLETE." + nudge := "Fahre fort. Wenn der Task erledigt ist, schreibe TASK_COMPLETE." a.log.ChatMessage("user", nudge) messages = append(messages, openai.UserMessage(nudge)) } return fmt.Errorf("maximale Turns (%d) erreicht ohne TASK_COMPLETE", maxTurns) } + +// isTaskComplete erkennt TASK_COMPLETE auch bei häufigen LLM-Tippfehlern +func isTaskComplete(response string) bool { + if strings.Contains(response, "TASK_COMPLETE") { + return true + } + typos := []string{ + "TUTK_COMPLETE", + "TASK_COMPLET", + "TASK_COMPLETED", + "TASK_COMPETE", + "TAKS_COMPLETE", + } + upper := strings.ToUpper(response) + for _, t := range typos { + if strings.Contains(upper, t) { + return true + } + } + return false +} diff --git a/output/ /home/jacek/projekte/goralphy/output/README.md b/output/ /home/jacek/projekte/goralphy/output/README.md new file mode 100644 index 0000000..d9084f5 --- /dev/null +++ b/output/ /home/jacek/projekte/goralphy/output/README.md @@ -0,0 +1 @@ +Das wird die Datei `README.md` mit dem Inhalt `""` erstellen. \ No newline at end of file diff --git "a/output/ /home/jacek/projekte/goralphy/output/README.md --in-content \"Hier sollte eine kurze Beschreibung des Projektoutputs enthalten sein. Beispielt: Berechnungsresultate, Versionen, Notizen etc.\"" "b/output/ /home/jacek/projekte/goralphy/output/README.md --in-content \"Hier sollte eine kurze Beschreibung des Projektoutputs enthalten sein. Beispielt: Berechnungsresultate, Versionen, Notizen etc.\"" new file mode 100644 index 0000000..3a2b134 --- /dev/null +++ "b/output/ /home/jacek/projekte/goralphy/output/README.md --in-content \"Hier sollte eine kurze Beschreibung des Projektoutputs enthalten sein. Beispielt: Berechnungsresultate, Versionen, Notizen etc.\"" @@ -0,0 +1,5 @@ +Wenn Sie möchten, dass die Datei komplett leer bleibt, können Sie auch den Inhalt leer lassen: + +TOOL:WRITE_FILE: /home/jacek/projekte/goralphy/output/README.md --in-content "" + +Bitte beachten Sie, dass dies die `README.md` Datei ersetzen würde, die schon existiert. \ No newline at end of file diff --git a/output/PRD.md b/output/PRD.md index 02657f1..95d6252 100644 --- a/output/PRD.md +++ b/output/PRD.md @@ -1,6 +1,6 @@ # Mein Projekt ## Tasks -- [ ] Projektstruktur anlegen -- [ ] Erstelle eine Datei hello.go mit einem Hello World Programm +- [x] Projektstruktur anlegen +- [x] Erstelle eine Datei hello.go mit einem Hello World Programm - [ ] Erstelle eine Datei README.md mit einer kurzen Projektbeschreibung