]> git.giacomolli.uk - onechat/blobdiff - tools.go
Let the agent keep user instructions
[onechat] / tools.go
index af500baf0af43c5be067dcb05f3adc8b13de6c86..009e3312404c646f53a8fea4284371264b420a70 100644 (file)
--- a/tools.go
+++ b/tools.go
@@ -49,11 +49,19 @@ type ToolChat interface {
 // the log as it happens: the call as a tool message, the result as an echo
 // message. The call is durable before its tool runs, so the log never misses an
 // action outside the agent. Commands and files run as the user in the working
-// directory, with no sandbox.
+// directory, with no sandbox. Zoom with a name reads the log of a subagent. 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. The toolbox of a subagent has none of them, so these are unknown tools
+// there.
 type Toolbox struct {
-       log     ToolLog
-       chat    ToolChat
-       workdir string
+       log       ToolLog
+       chat      ToolChat
+       subagents *Subagents
+       runs      *SubagentRuns
+       whatsapp  *WhatsApp
+       schedules *Schedules
+       workdir   string
 }
 
 // Call logs the call of the tool name with its JSON arguments, makes the log
@@ -92,7 +100,11 @@ func (b *Toolbox) run(ctx context.Context, name, arguments string) string {
        case "zoom":
                var args ToolZoomArguments
                err = toolDecodeArguments(arguments, &args)
-               if err == nil {
+               switch {
+               case err != nil:
+               case args.Name != nil:
+                       output, err = b.zoomAgent(ctx, *args.Name)
+               default:
                        output, err = b.zoom(args.ID, args.N)
                }
        case "date":
@@ -125,6 +137,68 @@ func (b *Toolbox) run(ctx context.Context, name, arguments string) string {
                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:
+                       err = fmt.Errorf("unknown tool %q", name)
+               case err == nil:
+                       output, err = b.runs.Spawn(ctx, args.Tasks, args.Effort)
+               }
+       case "tell":
+               var args ToolTellArguments
+               err = toolDecodeArguments(arguments, &args)
+               switch {
+               case b.runs == nil:
+                       err = fmt.Errorf("unknown tool %q", name)
+               case err == nil:
+                       output, err = b.runs.Tell(ctx, args.Name, args.Message)
+               }
+       case "whatsapp_find":
+               var args ToolWhatsAppFindArguments
+               err = toolDecodeArguments(arguments, &args)
+               switch {
+               case b.whatsapp == nil:
+                       err = fmt.Errorf("unknown tool %q", name)
+               case err == nil:
+                       output, err = b.whatsapp.Find(ctx, args.Name)
+               }
+       case "whatsapp_send":
+               var args ToolWhatsAppSendArguments
+               err = toolDecodeArguments(arguments, &args)
+               switch {
+               case b.whatsapp == nil:
+                       err = fmt.Errorf("unknown tool %q", name)
+               case err == nil:
+                       output, err = b.whatsapp.Send(ctx, args.ID, args.Chat, args.Text)
+               }
+       case "schedule_set":
+               var args ToolScheduleSetArguments
+               err = toolDecodeArguments(arguments, &args)
+               switch {
+               case b.schedules == nil:
+                       err = fmt.Errorf("unknown tool %q", name)
+               case err == nil:
+                       output, err = b.schedules.Set(args.Text, args.At, args.Cron)
+               }
+       case "schedule_list":
+               err = toolDecodeArguments(arguments, &struct{}{})
+               switch {
+               case b.schedules == nil:
+                       err = fmt.Errorf("unknown tool %q", name)
+               case err == nil:
+                       output = b.schedules.List()
+               }
+       case "schedule_remove":
+               var args ToolScheduleRemoveArguments
+               err = toolDecodeArguments(arguments, &args)
+               switch {
+               case b.schedules == nil:
+                       err = fmt.Errorf("unknown tool %q", name)
+               case err == nil:
+                       output, err = b.schedules.Remove(args.ID)
+               }
        default:
                err = fmt.Errorf("unknown tool %q", name)
        }
@@ -136,6 +210,16 @@ func (b *Toolbox) run(ctx context.Context, name, arguments string) string {
        return output
 }
 
+// zoomAgent returns the whole log of the subagent name.
+func (b *Toolbox) zoomAgent(ctx context.Context, name string) (string, error) {
+       subagent, err := b.subagents.Get(ctx, name)
+       if err != nil {
+               return "", err
+       }
+
+       return subagent.Show()
+}
+
 // zoom returns message id whole for n = 1, or else the two lines under the line
 // id+n.
 func (b *Toolbox) zoom(id, n int) (string, error) {
@@ -307,10 +391,12 @@ func (b *Toolbox) path(path string) string {
        return filepath.Join(b.workdir, path)
 }
 
-// ToolZoomArguments are the arguments of zoom.
+// ToolZoomArguments are the arguments of zoom. A Name that is not nil names
+// the subagent whose whole log zoom gives, and then ID and N are not used.
 type ToolZoomArguments struct {
-       ID int `json:"id"`
-       N  int `json:"n"`
+       ID   int     `json:"id"`
+       N    int     `json:"n"`
+       Name *string `json:"name"`
 }
 
 // ToolDateArguments are the arguments of date.
@@ -341,6 +427,44 @@ type ToolEditArguments struct {
        New  string `json:"new"`
 }
 
+// ToolSpawnArguments are the arguments of spawn. A nil Effort is the effort of
+// the agent.
+type ToolSpawnArguments struct {
+       Tasks  []string `json:"tasks"`
+       Effort *string  `json:"effort"`
+}
+
+// ToolTellArguments are the arguments of tell.
+type ToolTellArguments struct {
+       Name    string `json:"name"`
+       Message string `json:"message"`
+}
+
+// ToolWhatsAppFindArguments are the arguments of whatsapp_find.
+type ToolWhatsAppFindArguments struct {
+       Name string `json:"name"`
+}
+
+// ToolWhatsAppSendArguments are the arguments of whatsapp_send.
+type ToolWhatsAppSendArguments struct {
+       ID   string `json:"id"`
+       Chat string `json:"chat"`
+       Text string `json:"text"`
+}
+
+// ToolScheduleSetArguments are the arguments of schedule_set. Exactly one of At
+// and Cron is not nil.
+type ToolScheduleSetArguments struct {
+       Text string  `json:"text"`
+       At   *string `json:"at"`
+       Cron *string `json:"cron"`
+}
+
+// ToolScheduleRemoveArguments are the arguments of schedule_remove.
+type ToolScheduleRemoveArguments struct {
+       ID int `json:"id"`
+}
+
 // ToolHeadTail keeps the first and the last toolClipBytes bytes written to it,
 // and counts the bytes between them that it drops.
 type ToolHeadTail struct {