diff --git a/agent/loop.go b/agent/loop.go
index b96a655..a546022 100644
--- a/agent/loop.go
+++ b/agent/loop.go
@@ -2,6 +2,7 @@ package agent
import (
"context"
+ "encoding/json"
"fmt"
"strings"
"time"
@@ -100,7 +101,6 @@ func (a *AgentLoop) Run() error {
func (a *AgentLoop) runTask(task prd.Task) error {
executor := NewToolExecutor(a.workDir)
- // Frischer Kontext pro Task
messages := []openai.ChatCompletionMessageParamUnion{
openai.SystemMessage(systemPrompt),
openai.UserMessage(fmt.Sprintf(
@@ -133,7 +133,7 @@ func (a *AgentLoop) runTask(task prd.Task) error {
openai.ChatCompletionNewParams{
Model: a.model,
Messages: messages,
- Tools: Tools, // β Tool Calling
+ Tools: Tools,
},
)
cancel()
@@ -147,12 +147,19 @@ func (a *AgentLoop) runTask(task prd.Task) error {
}
choice := resp.Choices[0]
-
- // Antwort zur History hinzufΓΌgen
messages = append(messages, choice.Message.ToParam())
+ // Echte Tool-Calls vom SDK
+ toolCalls := choice.Message.ToolCalls
+
+ // Fallback: XML-Format parsen wenn Modell kein natives Tool Calling nutzt
+ if len(toolCalls) == 0 && strings.Contains(choice.Message.Content, "
+// hello.go
+// package main...
+//
+func parseXMLToolCalls(content string) []openai.ChatCompletionMessageToolCall {
+ var calls []openai.ChatCompletionMessageToolCall
+ remaining := content
+ callID := 0
+
+ for {
+ // Funktionsname extrahieren
+ start := strings.Index(remaining, "")
+ if nameEnd == -1 {
+ break
+ }
+ funcName := strings.TrimSpace(remaining[nameStart : nameStart+nameEnd])
+
+ // Block bis extrahieren
+ blockEnd := strings.Index(remaining, "")
+ if blockEnd == -1 {
+ break
+ }
+ block := remaining[start : blockEnd+len("")]
+
+ // Parameter extrahieren und als JSON serialisieren
+ params := extractXMLParams(block)
+ argsJSON, err := json.Marshal(params)
+ if err != nil {
+ remaining = remaining[blockEnd+len(""):]
+ continue
+ }
+
+ callID++
+ calls = append(calls, openai.ChatCompletionMessageToolCall{
+ ID: fmt.Sprintf("xml-call-%d", callID),
+ Type: "function",
+ Function: openai.ChatCompletionMessageToolCallFunction{
+ Name: funcName,
+ Arguments: string(argsJSON),
+ },
+ })
+
+ remaining = remaining[blockEnd+len(""):]
+ }
+
+ return calls
+}
+
+// extractXMLParams extrahiert alle value aus einem Block
+func extractXMLParams(block string) map[string]string {
+ params := make(map[string]string)
+ remaining := block
+
+ for {
+ start := strings.Index(remaining, "")
+ if keyEnd == -1 {
+ break
+ }
+ key := strings.TrimSpace(remaining[keyStart : keyStart+keyEnd])
+
+ // Value extrahieren
+ valueStart := keyStart + keyEnd + 1
+ closeTag := ""
+ valueEnd := strings.Index(remaining[valueStart:], closeTag)
+ if valueEnd == -1 {
+ break
+ }
+ value := strings.TrimSpace(remaining[valueStart : valueStart+valueEnd])
+
+ params[key] = value
+ remaining = remaining[valueStart+valueEnd+len(closeTag):]
+ }
+
+ return params
+}
+
// βββ Hilfsfunktionen βββββββββββββββββββββββββββββββββββββ
func truncate(s string, max int) string {
@@ -225,7 +326,6 @@ func formatResponse(resp *openai.ChatCompletion, elapsed time.Duration) string {
resp.Usage.TotalTokens,
))
- // Tool-Calls anzeigen
if len(resp.Choices[0].Message.ToolCalls) > 0 {
sb.WriteString(" Tool-Calls :\n")
for _, tc := range resp.Choices[0].Message.ToolCalls {
@@ -234,12 +334,12 @@ func formatResponse(resp *openai.ChatCompletion, elapsed time.Duration) string {
truncate(tc.Function.Arguments, 100),
))
}
- } else {
- content := resp.Choices[0].Message.Content
+ } else if content := resp.Choices[0].Message.Content; content != "" {
sb.WriteString(" Content :\n")
for _, line := range strings.Split(content, "\n") {
sb.WriteString(fmt.Sprintf(" %s\n", line))
}
}
+
return sb.String()
}