blob: 8ff5d6b9c22f00679324d4ff9b0388d4f9d4bf55 [file] [log] [blame]
package loop
import (
"context"
"encoding/json"
"fmt"
"strings"
"time"
"dodo.cloud/neo/tools"
"github.com/anthropics/anthropic-sdk-go"
)
type AnthropicAgent struct {
reg tools.Registry
client anthropic.Client
}
func (a *AnthropicAgent) Run(todo *ToDo) error {
sp := fmt.Sprintf(systemPrompt, ToDoJSONSchema())
var toolParams []anthropic.ToolParam
for _, t := range a.reg.All() {
schema, err := GetToolSchema(t.InputSchema())
if err != nil {
return err
}
toolParams = append(toolParams, anthropic.ToolParam{
Name: t.Name(),
Description: anthropic.String(t.Description()),
InputSchema: schema,
})
}
tools := make([]anthropic.ToolUnionParam, len(toolParams))
for i, toolParam := range toolParams {
tools[i] = anthropic.ToolUnionParam{OfTool: &toolParam}
}
k, err := json.MarshalIndent(todo, "", "\t")
if err != nil {
return err
}
for {
items := findActionableItems(todo, "assistant")
if len(items) == 0 {
time.Sleep(30 * time.Second)
continue
}
var itemIds []string
var messages []anthropic.MessageParam
for _, i := range items {
itemIds = append(itemIds, i.ID)
}
messages = append(messages, anthropic.NewUserMessage(anthropic.NewTextBlock(string(k))))
messages = append(messages, anthropic.NewUserMessage(anthropic.NewTextBlock(
fmt.Sprintf("Work on TODO item: %s", strings.Join(itemIds, ", ")))))
for {
resp, err := a.client.Messages.New(context.TODO(), anthropic.MessageNewParams{
MaxTokens: 10240,
System: []anthropic.TextBlockParam{
{Text: sp},
},
Messages: messages,
Model: anthropic.ModelClaudeOpus4_6,
Tools: tools,
})
if err != nil {
return err
}
fmt.Printf("--- STOP_REASON: %s\n", resp.StopReason)
messages = append(messages, resp.ToParam())
var toolResults []anthropic.ContentBlockParamUnion
for _, block := range resp.Content {
switch v := block.AsAny().(type) {
case anthropic.TextBlock:
fmt.Printf("AI: %s\n", v.Text)
case anthropic.ToolUseBlock:
t := a.reg.Get(v.Name)
if t == nil {
toolResults = append(toolResults, anthropic.NewToolResultBlock(v.ID, fmt.Sprintf("unknown tool %q", v.Name), true))
continue
}
args := v.JSON.Input.Raw()
fmt.Printf("CALLING TOOL: %s %s\n", v.Name, args)
out, err := t.Call(string(args))
if err != nil {
fmt.Printf("ERR: %s\n", err.Error())
toolResults = append(toolResults, anthropic.NewToolResultBlock(v.ID, err.Error(), true))
} else {
toolResults = append(toolResults, anthropic.NewToolResultBlock(v.ID, out, false))
}
}
}
if len(toolResults) == 0 {
break
}
messages = append(messages, anthropic.NewUserMessage(toolResults...))
}
for _, i := range items {
i.AssignedTo = "user"
}
}
}