]> git.giacomolli.uk - onechat/blobdiff - prompt.go
Deliver routed WhatsApp batches to children
[onechat] / prompt.go
index e651988105b1aedd49d5dd775ccd412cf44c5639..36fda3288de8778c156fc51f35e79122b1015725 100644 (file)
--- a/prompt.go
+++ b/prompt.go
@@ -101,11 +101,11 @@ starting "[Name]", between your tool calls or as a new turn. Never wait for one
 running.
 
 You are in persistent mode: a reply with no tool call is your final answer, and
 running.
 
 You are in persistent mode: a reply with no tool call is your final answer, and
-it ends your turn. You act again only when the user writes. So keep going until
-the user's task is done, or until only the user can unblock it. Answer a
-question asked in the middle of a task, then go on with the task in the same
-turn. When the user says "continue", resume the latest unfinished task from the
-view.
+it ends your turn. You act again when a message or your own schedule wakes you.
+So keep going until the user's task is done, or until only the user can unblock
+it. Answer a question asked in the middle of a task, then go on with the task
+in the same turn. When the user says "continue", resume the latest unfinished
+task from the view.
 
 # Compactions
 
 
 # Compactions
 
@@ -142,6 +142,17 @@ exactly. Tag each item with its kind ("user: ...; echo: ..."), and credit quoted
 text to its real author. Never make anything look further along than it was. If
 told the line is too long, shorten it. Non-ASCII characters cost 2-4 bytes.`
 
 text to its real author. Never make anything look further along than it was. If
 told the line is too long, shorten it. Non-ASCII characters cost 2-4 bytes.`
 
+// promptChildrenText gives the root the tools and consent rules for children.
+const promptChildrenText = `
+
+Use agent_create for permanent children, whose areas are in the state.
+Use tell for children and subagents, and zoom("Name") for their memory.
+Pass area messages from mixed chats to the right child with sender, date, and
+words. Never send a WhatsApp reply drafted by a child without the user's
+agreement.
+Propose routing a source that talks only about one area to its child.
+Set or remove a route only after the user agrees.`
+
 // promptSubagentText is the system prompt of a subagent, from the subagent
 // prompt of the reference design: its head, then the doc of the view, without
 // the parts on devices and images. A subagent gets the view of the agent, then
 // promptSubagentText is the system prompt of a subagent, from the subagent
 // prompt of the reference design: its head, then the doc of the view, without
 // the parts on devices and images. A subagent gets the view of the agent, then
@@ -188,20 +199,41 @@ whole chat.`
 // cache of the turns.
 func prompt(name, instructionsPath, instructions string) string {
        text := strings.NewReplacer(promptName, name, promptInstructionsPath, instructionsPath).Replace(promptText)
 // cache of the turns.
 func prompt(name, instructionsPath, instructions string) string {
        text := strings.NewReplacer(promptName, name, promptInstructionsPath, instructionsPath).Replace(promptText)
+       text = strings.Replace(text, "\n\n# Compactions", promptChildrenText+"\n\n# Compactions", 1)
+
        return promptWithInstructions(text, promptTaskSentence, promptInstructionsClause, instructions)
 }
 
        return promptWithInstructions(text, promptTaskSentence, promptInstructionsClause, instructions)
 }
 
+// promptChild returns the prompt of a child with its area and reporting rules.
+// Its instructions file belongs to the child, not to the parent.
+func promptChild(name, parent, responsibility, instructionsPath, instructions string) string {
+       text := prompt(name, instructionsPath, "")
+       text = strings.Replace(text, "You are "+name+", an AI agent that works for one user in a single chat that never\nends.", "You are "+name+", a child agent of "+parent+".", 1)
+       text = strings.Replace(text, promptTaskSentence, `Do the tasks of your area yourself, with your tools.
+You are responsible for: `+responsibility+`
+Work only in this area. Report to `+parent+` only what needs the parent or the
+user: a decision, a deadline, a problem, a question you cannot settle, or a
+message outside your area. Your final reply is your report to the parent.
+End your turn with an empty reply when nothing needs the parent or the user.
+Send nothing to WhatsApp. Draft replies in your report instead, so the parent
+can ask the user before sending.`, 1)
+       text = strings.Replace(text, promptChildrenText, "", 1)
+
+       return promptWithInstructions(text, "Do the tasks of your area yourself, with your tools.", promptInstructionsClause, instructions)
+}
+
 // promptSubagent returns the system prompt of a subagent of the agent name,
 // with the instructions of the user at its end, as prompt does.
 func promptSubagent(name, instructions string) string {
        text := strings.ReplaceAll(promptSubagentText, promptName, name)
 // promptSubagent returns the system prompt of a subagent of the agent name,
 // with the instructions of the user at its end, as prompt does.
 func promptSubagent(name, instructions string) string {
        text := strings.ReplaceAll(promptSubagentText, promptName, name)
+
        return promptWithInstructions(text, promptSubagentTaskSentence, promptSubagentInstructionsClause, instructions)
 }
 
 // promptTools returns the function tools of every call of the agent: the tools
        return promptWithInstructions(text, promptSubagentTaskSentence, promptSubagentInstructionsClause, instructions)
 }
 
 // promptTools returns the function tools of every call of the agent: the tools
-// of promptSubagentTools, then spawn, tell, the WhatsApp tools, and the
-// schedule tools. A compaction sends them too and never calls them, because a
-// change of the tools ends the shared prompt cache.
+// of promptSubagentTools, then spawn, agent_create, tell, the WhatsApp tools,
+// the route tools, and the schedule tools. A compaction sends them too and
+// never calls them, because a change of the tools ends the shared prompt cache.
 func promptTools() []ModelTool {
        return append(promptSubagentTools(), ModelTool{
                Type:        "function",
 func promptTools() []ModelTool {
        return append(promptSubagentTools(), ModelTool{
                Type:        "function",
@@ -220,12 +252,21 @@ func promptTools() []ModelTool {
                        },
                }),
                Strict: true,
                        },
                }),
                Strict: true,
+       }, ModelTool{
+               Type:        "function",
+               Name:        "agent_create",
+               Description: "Create and start a permanent child for an area, with your model and effort. Give a short capitalized name for the area, such as House, with 2 to 32 ASCII letters. Use tell to give it a task. Only the root can create children.",
+               Parameters: promptObjectSchema(map[string]any{
+                       "name":           promptStringSchema("The new child name."),
+                       "responsibility": promptStringSchema("The area that the child owns."),
+               }),
+               Strict: true,
        }, ModelTool{
                Type:        "function",
                Name:        "tell",
        }, ModelTool{
                Type:        "function",
                Name:        "tell",
-               Description: `Send a message to a subagent, by name. One at work reads it between its tool calls, and its report answers it; a finished one goes on from its chat, and its reply reaches you as a message "[Name] reply".`,
+               Description: `Send a message to your child or a subagent, by name. A child wakes and reports to you. One at work reads it between its tool calls, and its report answers it; a finished one goes on from its chat, and its reply reaches you as a message "[Name] reply".`,
                Parameters: promptObjectSchema(map[string]any{
                Parameters: promptObjectSchema(map[string]any{
-                       "name":    promptStringSchema("The name of the subagent."),
+                       "name":    promptStringSchema("The name of your child or subagent."),
                        "message": promptStringSchema("The message."),
                }),
                Strict: true,
                        "message": promptStringSchema("The message."),
                }),
                Strict: true,
@@ -247,6 +288,29 @@ func promptTools() []ModelTool {
                        "text": promptStringSchema("The text of the message."),
                }),
                Strict: true,
                        "text": promptStringSchema("The text of the message."),
                }),
                Strict: true,
+       }, ModelTool{
+               Type:        "function",
+               Name:        "route",
+               Description: "Route a source to your child, only after the user agrees. Use whatsapp:CHAT-ID with the ID from whatsapp_find or a [WhatsApp] message.",
+               Parameters: promptObjectSchema(map[string]any{
+                       "source": promptStringSchema("The source key, whatsapp:CHAT-ID."),
+                       "agent":  promptStringSchema("The name of your child."),
+               }),
+               Strict: true,
+       }, ModelTool{
+               Type:        "function",
+               Name:        "unroute",
+               Description: "Remove a source route, only after the user agrees. New inputs go to you.",
+               Parameters: promptObjectSchema(map[string]any{
+                       "source": promptStringSchema("The source key, whatsapp:CHAT-ID."),
+               }),
+               Strict: true,
+       }, ModelTool{
+               Type:        "function",
+               Name:        "routes",
+               Description: "List source routes to your children.",
+               Parameters:  promptObjectSchema(map[string]any{}),
+               Strict:      true,
        }, ModelTool{
                Type:        "function",
                Name:        "schedule_set",
        }, ModelTool{
                Type:        "function",
                Name:        "schedule_set",