X-Git-Url: https://git.giacomolli.uk/onechat/blobdiff_plain/e737005f89c7c663e1636830001730ad79396bdc..8fb85e5647f82e029956d81be29b3a5ac3490636:/tools.go?ds=sidebyside diff --git a/tools.go b/tools.go index 009e331..4c00350 100644 --- a/tools.go +++ b/tools.go @@ -71,12 +71,12 @@ type Toolbox struct { func (b *Toolbox) Call(ctx context.Context, name, arguments string) (string, error) { _, err := b.log.Append("tool", toolCallText(name, arguments)) if err != nil { - return "", err + return "", fmt.Errorf("append tool call: %w", err) } err = b.log.Flush(ctx) if err != nil && ctx.Err() == nil { - return "", err + return "", fmt.Errorf("flush tool call: %w", err) } output := "not run: the turn was interrupted" @@ -86,7 +86,7 @@ func (b *Toolbox) Call(ctx context.Context, name, arguments string) (string, err _, err = b.log.Append("echo", output) if err != nil { - return "", err + return "", fmt.Errorf("append tool result: %w", err) } return output, nil @@ -94,11 +94,15 @@ func (b *Toolbox) Call(ctx context.Context, name, arguments string) (string, err // run runs one tool and returns its output, or its error as text. func (b *Toolbox) run(ctx context.Context, name, arguments string) string { - var output string - var err error + var ( + output string + err error + ) + switch name { case "zoom": var args ToolZoomArguments + err = toolDecodeArguments(arguments, &args) switch { case err != nil: @@ -109,36 +113,42 @@ func (b *Toolbox) run(ctx context.Context, name, arguments string) string { } case "date": var args ToolDateArguments + err = toolDecodeArguments(arguments, &args) if err == nil { output, err = b.date(args.ID) } case "shell": var args ToolShellArguments + err = toolDecodeArguments(arguments, &args) if err == nil { output = b.shell(ctx, args.Command) } case "read": var args ToolPathArguments + err = toolDecodeArguments(arguments, &args) if err == nil { output, err = b.read(args.Path) } case "write": var args ToolWriteArguments + err = toolDecodeArguments(arguments, &args) if err == nil { output, err = b.write(args.Path, args.Text) } case "edit": var args ToolEditArguments + err = toolDecodeArguments(arguments, &args) if err == nil { output, err = b.edit(args.Path, args.Old, args.New) } case "spawn": var args ToolSpawnArguments + err = toolDecodeArguments(arguments, &args) switch { case b.runs == nil: @@ -148,6 +158,7 @@ func (b *Toolbox) run(ctx context.Context, name, arguments string) string { } case "tell": var args ToolTellArguments + err = toolDecodeArguments(arguments, &args) switch { case b.runs == nil: @@ -157,6 +168,7 @@ func (b *Toolbox) run(ctx context.Context, name, arguments string) string { } case "whatsapp_find": var args ToolWhatsAppFindArguments + err = toolDecodeArguments(arguments, &args) switch { case b.whatsapp == nil: @@ -166,6 +178,7 @@ func (b *Toolbox) run(ctx context.Context, name, arguments string) string { } case "whatsapp_send": var args ToolWhatsAppSendArguments + err = toolDecodeArguments(arguments, &args) switch { case b.whatsapp == nil: @@ -175,6 +188,7 @@ func (b *Toolbox) run(ctx context.Context, name, arguments string) string { } case "schedule_set": var args ToolScheduleSetArguments + err = toolDecodeArguments(arguments, &args) switch { case b.schedules == nil: @@ -192,6 +206,7 @@ func (b *Toolbox) run(ctx context.Context, name, arguments string) string { } case "schedule_remove": var args ToolScheduleRemoveArguments + err = toolDecodeArguments(arguments, &args) switch { case b.schedules == nil: @@ -234,18 +249,20 @@ func (b *Toolbox) zoom(id, n int) (string, error) { if n == 1 { message, err := b.chat.Message(id) if err != nil { - return "", err + return "", fmt.Errorf("read zoom message: %w", err) } return leafSource(message), nil } level := bits.TrailingZeros(uint(n)) - 1 + var lines []string + for _, index := range []int{2 * id / n, 2*id/n + 1} { node, built, err := b.chat.Node(level, index) if err != nil { - return "", err + return "", fmt.Errorf("read zoom node: %w", err) } text := viewPending @@ -267,12 +284,12 @@ func (b *Toolbox) date(id int) (string, error) { message, err := b.chat.Message(id) if err != nil { - return "", err + return "", fmt.Errorf("read dated message: %w", err) } date, err := time.Parse(time.RFC3339Nano, message.Date) if err != nil { - return "", err + return "", fmt.Errorf("parse message date: %w", err) } return date.Local().Format("Monday 2006-01-02 15:04:05 -07:00"), nil @@ -298,7 +315,9 @@ func (b *Toolbox) shell(ctx context.Context, command string) string { err := cmd.Run() text := output.String() + var exit *exec.ExitError + switch { case ctx.Err() != nil: text += "\n[interrupted]" @@ -317,7 +336,7 @@ func (b *Toolbox) shell(ctx context.Context, command string) string { func (b *Toolbox) read(path string) (text string, err error) { file, err := os.Open(b.path(path)) if err != nil { - return "", err + return "", fmt.Errorf("open tool file: %w", err) } defer func() { @@ -327,7 +346,7 @@ func (b *Toolbox) read(path string) (text string, err error) { output := &ToolHeadTail{} _, err = io.Copy(output, file) if err != nil { - return "", err + return "", fmt.Errorf("read tool file: %w", err) } return output.String(), nil @@ -339,12 +358,12 @@ func (b *Toolbox) write(path, text string) (string, error) { path = b.path(path) err := os.MkdirAll(filepath.Dir(path), 0o755) if err != nil { - return "", err + return "", fmt.Errorf("create tool file directory: %w", err) } err = os.WriteFile(path, []byte(text), 0o644) if err != nil { - return "", err + return "", fmt.Errorf("write tool file: %w", err) } return fmt.Sprintf("wrote %d bytes to %s", len(text), path), nil @@ -356,7 +375,7 @@ func (b *Toolbox) edit(path, old, replacement string) (string, error) { path = b.path(path) data, err := os.ReadFile(path) if err != nil { - return "", err + return "", fmt.Errorf("read file to edit: %w", err) } if old == "" { @@ -370,12 +389,12 @@ func (b *Toolbox) edit(path, old, replacement string) (string, error) { info, err := os.Stat(path) if err != nil { - return "", err + return "", fmt.Errorf("read file mode: %w", err) } err = os.WriteFile(path, []byte(strings.Replace(string(data), old, replacement, 1)), info.Mode().Perm()) if err != nil { - return "", err + return "", fmt.Errorf("write edited file: %w", err) } return "edited " + path, nil @@ -530,6 +549,7 @@ func toolClip(text string) string { func toolDecodeArguments(arguments string, args any) error { decoder := json.NewDecoder(strings.NewReader(arguments)) decoder.DisallowUnknownFields() + err := decoder.Decode(args) if err != nil { return fmt.Errorf("arguments: %w", err)