X-Git-Url: https://git.giacomolli.uk/onechat/blobdiff_plain/5a93b6124068c2a8748fc0bfbb2a2d151815bcf0..4343ca5fb6cc86eb887951f4fe16063bab29a238:/tools.go?ds=sidebyside diff --git a/tools.go b/tools.go index b4fb075..96cbb97 100644 --- a/tools.go +++ b/tools.go @@ -53,8 +53,9 @@ type ToolChat interface { // subagent's log. The toolbox of the agent has the runs of its subagents for // spawn and tell, the WhatsApp link for the WhatsApp tools, and the schedules // for the schedule tools. Each permanent agent has the parent-child queue. Only -// the root has child creation. A child has no WhatsApp link or child creation. -// The toolbox of a subagent has none of them, so these are unknown tools there. +// the root has child creation and source routes. A child has neither of them +// nor a WhatsApp link. The toolbox of a subagent has none of them, so these are +// unknown tools there. type Toolbox struct { log ToolLog chat ToolChat @@ -66,13 +67,16 @@ type Toolbox struct { agentName string messages *DaemonMessages children *DaemonChildren + routes *Routes + images *ImageStore } // Call logs the call of the tool name with its JSON arguments, makes the log -// durable, runs the tool, and logs its clipped output, which it returns. A -// failed tool gives its error as the output. An error of Call itself is an -// error of the log. When ctx ends before the flush, the tool does not run. -func (b *Toolbox) Call(ctx context.Context, name, arguments string) (string, error) { +// durable, runs the tool, and logs its clipped text. It returns that text or +// the text and image parts of a single-message zoom. Pixels never enter the +// log. A failed tool gives its error as the output. An error of Call itself is +// an error of the log. When ctx ends before the flush, the tool does not run. +func (b *Toolbox) Call(ctx context.Context, name, arguments string) (any, error) { _, err := b.log.Append("tool", toolCallText(name, arguments)) if err != nil { return "", fmt.Errorf("append tool call: %w", err) @@ -88,12 +92,26 @@ func (b *Toolbox) Call(ctx context.Context, name, arguments string) (string, err output = toolClip(b.run(ctx, name, arguments)) } + var ( + result any = output + resultErr error + ) + + if err == nil { + result, resultErr = imageToolOutput(b, name, arguments, output) + } + + if resultErr != nil { + output = "error: " + resultErr.Error() + result = output + } + _, err = b.log.Append("echo", output) if err != nil { return "", fmt.Errorf("append tool result: %w", err) } - return output, nil + return result, nil } // run runs one tool and returns its output, or its error as text. @@ -170,6 +188,36 @@ func (b *Toolbox) run(ctx context.Context, name, arguments string) string { case err == nil: output, err = b.children.Create(args.Name, args.Responsibility) } + case "route", "unroute", "routes": + var args ToolRouteArguments + + switch name { + case "routes": + err = toolDecodeArguments(arguments, &struct{}{}) + case "unroute": + var source ToolRouteSourceArguments + + err = toolDecodeArguments(arguments, &source) + args.Source = source.Source + default: + err = toolDecodeArguments(arguments, &args) + } + + switch { + case b.routes == nil: + err = fmt.Errorf("unknown tool %q", name) + case err != nil: + case name == "routes": + output = b.routes.List() + case name == "route" && (b.messages == nil || b.messages.Child(b.agentName, args.Agent) == nil): + err = errors.New("the agent must be a child of the root") + default: + err = b.routes.Set(args.Source, args.Agent) + output = "Route removed." + if name == "route" { + output = "Route set." + } + } case "tell": var args ToolTellArguments @@ -484,6 +532,17 @@ type ToolAgentCreateArguments struct { Responsibility string `json:"responsibility"` } +// ToolRouteArguments are the arguments of route. +type ToolRouteArguments struct { + Source string `json:"source"` + Agent string `json:"agent"` +} + +// ToolRouteSourceArguments are the arguments of unroute. +type ToolRouteSourceArguments struct { + Source string `json:"source"` +} + // ToolTellArguments are the arguments of tell. type ToolTellArguments struct { Name string `json:"name"`