Still not super sure how to represent these agents in code. It doesn't make the most amount of sense to keep them in structs. A curried function is more like it, with system prompt and tooling. Maybe that's what I'll end up doing.
154 lines
4.2 KiB
Go
154 lines
4.2 KiB
Go
package agents
|
|
|
|
import (
|
|
"errors"
|
|
"os"
|
|
"screenmark/screenmark/agents/client"
|
|
"time"
|
|
|
|
"github.com/charmbracelet/log"
|
|
)
|
|
|
|
const OrchestratorPrompt = `
|
|
You are an Orchestrator for various AI agents.
|
|
|
|
The user will send you images and you have to determine which agents you have to call, in order to best help the user.
|
|
|
|
You might decide no agent needs to be called.
|
|
|
|
The agents are available as tool calls.
|
|
|
|
Agents available:
|
|
|
|
eventLocationAgent
|
|
Use it when you think the image contains an event or a location of any sort. This can be an event page, a map, an address or a date.
|
|
This could also be a conversation describing an event.
|
|
|
|
noteAgent
|
|
Use when there is ANY text on the image.
|
|
|
|
contactAgent
|
|
|
|
Use it when the image contains information relating a person.
|
|
|
|
noAction
|
|
When you think there is no more information to extract from the image.
|
|
|
|
Always call agents in parallel if you need to call more than 1.
|
|
|
|
Do not call the agent if you do not think it is relevant for the image.
|
|
`
|
|
|
|
const OrchestratorTools = `
|
|
[
|
|
{
|
|
"type": "function",
|
|
"function": {
|
|
"name": "eventLocationAgent",
|
|
"description": "Use when there is an event or location on the image. This could be in writing form",
|
|
"parameters": {
|
|
"type": "object",
|
|
"properties": {},
|
|
"required": []
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"type": "function",
|
|
"function": {
|
|
"name": "noteAgent",
|
|
"description": "Use when there is any text on the image, this can be code/text/formulas any writing",
|
|
"parameters": {
|
|
"type": "object",
|
|
"properties": {},
|
|
"required": []
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"type": "function",
|
|
"function": {
|
|
"name": "contactAgent",
|
|
"description": "Use when then image contains some person or contact",
|
|
"parameters": {
|
|
"type": "object",
|
|
"properties": {},
|
|
"required": []
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"type": "function",
|
|
"function": {
|
|
"name": "noAction",
|
|
"description": "Use when you are sure nothing can be done about this image anymore",
|
|
"parameters": {
|
|
"type": "object",
|
|
"properties": {},
|
|
"required": []
|
|
}
|
|
}
|
|
}
|
|
]`
|
|
|
|
type OrchestratorAgent struct {
|
|
Client client.AgentClient
|
|
|
|
log log.Logger
|
|
}
|
|
|
|
type Status struct {
|
|
Ok bool `json:"ok"`
|
|
}
|
|
|
|
func NewOrchestratorAgent(eventLocationAgent EventLocationAgent, noteAgent NoteAgent, contactAgent ContactAgent, imageName string, imageData []byte) (OrchestratorAgent, error) {
|
|
agent, err := client.CreateAgentClient(log.NewWithOptions(os.Stdout, log.Options{
|
|
ReportTimestamp: true,
|
|
TimeFormat: time.Kitchen,
|
|
Prefix: "Orchestrator 🎼",
|
|
}))
|
|
|
|
if err != nil {
|
|
return OrchestratorAgent{}, err
|
|
}
|
|
|
|
agent.ToolHandler.AddTool("eventLocationAgent", func(info client.ToolHandlerInfo, args string, call client.ToolCall) (any, error) {
|
|
// We need a way to keep track of this async?
|
|
// Probably just a DB, because we don't want to wait. The orchistrator shouldnt wait for this stuff to finish.
|
|
|
|
go eventLocationAgent.client.RunAgent(eventLocationPrompt, eventLocationTools, "finish", info.UserId, info.ImageId, imageName, imageData)
|
|
|
|
return Status{
|
|
Ok: true,
|
|
}, nil
|
|
})
|
|
|
|
agent.ToolHandler.AddTool("noteAgent", func(info client.ToolHandlerInfo, args string, call client.ToolCall) (any, error) {
|
|
go noteAgent.GetNotes(info.UserId, info.ImageId, imageName, imageData)
|
|
|
|
return Status{
|
|
Ok: true,
|
|
}, nil
|
|
})
|
|
|
|
agent.ToolHandler.AddTool("contactAgent", func(info client.ToolHandlerInfo, args string, call client.ToolCall) (any, error) {
|
|
go contactAgent.client.RunAgent(contactPrompt, contactTools, "finish", info.UserId, info.ImageId, imageName, imageData)
|
|
|
|
return Status{
|
|
Ok: true,
|
|
}, nil
|
|
})
|
|
|
|
agent.ToolHandler.AddTool("noAction", func(info client.ToolHandlerInfo, args string, call client.ToolCall) (any, error) {
|
|
// To nothing
|
|
|
|
return Status{
|
|
Ok: true,
|
|
}, errors.New("Finished! Kinda bad return type but...")
|
|
})
|
|
|
|
return OrchestratorAgent{
|
|
Client: agent,
|
|
}, nil
|
|
}
|