feat(event): seperate event agent
This commit is contained in:
200
backend/agents/event_agent.go
Normal file
200
backend/agents/event_agent.go
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
package agents
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"os"
|
||||||
|
"screenmark/screenmark/.gen/haystack/haystack/model"
|
||||||
|
"screenmark/screenmark/agents/client"
|
||||||
|
"screenmark/screenmark/models"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/charmbracelet/log"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
const eventPrompt = `
|
||||||
|
You are an agent.
|
||||||
|
|
||||||
|
The user will send you images and you have to identify if they have any events or a place.
|
||||||
|
This could be a friend suggesting to meet, a conference, or anything that looks like an event.
|
||||||
|
|
||||||
|
There are various tools you can use to perform this task.
|
||||||
|
|
||||||
|
listEvents
|
||||||
|
Lists the users already existing events, you should do this before using createEvents to avoid creating duplicates.
|
||||||
|
|
||||||
|
createEvent
|
||||||
|
Use this to create a new events.
|
||||||
|
|
||||||
|
linkEvent
|
||||||
|
Links an image to a events.
|
||||||
|
|
||||||
|
finish
|
||||||
|
Call when there is nothing else to do.
|
||||||
|
`
|
||||||
|
|
||||||
|
const eventTools = `
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"type": "function",
|
||||||
|
"function": {
|
||||||
|
"name": "listEvents",
|
||||||
|
"description": "List the events the user already has.",
|
||||||
|
"parameters": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {},
|
||||||
|
"required": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "function",
|
||||||
|
"function": {
|
||||||
|
"name": "createEvent",
|
||||||
|
"description": "Use to create a new events",
|
||||||
|
"parameters": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"startDateTime": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The start time as an ISO string"
|
||||||
|
},
|
||||||
|
"endDateTime": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The end time as an ISO string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": ["name"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "function",
|
||||||
|
"function": {
|
||||||
|
"name": "linkEvent",
|
||||||
|
"description": "Use to link an already existing events to the image you were sent",
|
||||||
|
"parameters": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"eventId": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": ["eventsId"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "function",
|
||||||
|
"function": {
|
||||||
|
"name": "finish",
|
||||||
|
"description": "Call this when there is nothing left to do.",
|
||||||
|
"parameters": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {},
|
||||||
|
"required": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]`
|
||||||
|
|
||||||
|
type EventAgent struct {
|
||||||
|
client client.AgentClient
|
||||||
|
|
||||||
|
eventsModel models.EventModel
|
||||||
|
}
|
||||||
|
|
||||||
|
type listEventArguments struct{}
|
||||||
|
type createEventArguments struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
StartDateTime *string `json:"startDateTime"`
|
||||||
|
EndDateTime *string `json:"endDateTime"`
|
||||||
|
OrganizerName *string `json:"organizerName"`
|
||||||
|
}
|
||||||
|
type linkEventArguments struct {
|
||||||
|
EventID string `json:"eventId"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewEventAgent(eventsModel models.EventModel) (EventAgent, error) {
|
||||||
|
agentClient, err := client.CreateAgentClient(log.NewWithOptions(os.Stdout, log.Options{
|
||||||
|
ReportTimestamp: true,
|
||||||
|
TimeFormat: time.Kitchen,
|
||||||
|
Prefix: "Events 📍",
|
||||||
|
}))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return EventAgent{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
agent := EventAgent{
|
||||||
|
client: agentClient,
|
||||||
|
eventsModel: eventsModel,
|
||||||
|
}
|
||||||
|
|
||||||
|
agentClient.ToolHandler.AddTool("listEvents", func(info client.ToolHandlerInfo, args string, call client.ToolCall) (any, error) {
|
||||||
|
return agent.eventsModel.List(context.Background(), info.UserId)
|
||||||
|
})
|
||||||
|
|
||||||
|
agentClient.ToolHandler.AddTool("createEvent", func(info client.ToolHandlerInfo, _args string, call client.ToolCall) (any, error) {
|
||||||
|
args := createEventArguments{}
|
||||||
|
err := json.Unmarshal([]byte(_args), &args)
|
||||||
|
if err != nil {
|
||||||
|
return model.Events{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
layout := "2006-01-02T15:04:05Z"
|
||||||
|
|
||||||
|
startTime, err := time.Parse(layout, *args.StartDateTime)
|
||||||
|
if err != nil {
|
||||||
|
return model.Events{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
endTime, err := time.Parse(layout, *args.EndDateTime)
|
||||||
|
if err != nil {
|
||||||
|
return model.Events{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
events, err := agent.eventsModel.Save(ctx, info.UserId, model.Events{
|
||||||
|
Name: args.Name,
|
||||||
|
StartDateTime: &startTime,
|
||||||
|
EndDateTime: &endTime,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return model.Events{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = agent.eventsModel.SaveToImage(ctx, info.ImageId, events.ID)
|
||||||
|
if err != nil {
|
||||||
|
return model.Events{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return events, nil
|
||||||
|
})
|
||||||
|
|
||||||
|
agentClient.ToolHandler.AddTool("linkEvent", func(info client.ToolHandlerInfo, _args string, call client.ToolCall) (any, error) {
|
||||||
|
args := linkEventArguments{}
|
||||||
|
err := json.Unmarshal([]byte(_args), &args)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
contactUuid, err := uuid.Parse(args.EventID)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
agent.eventsModel.SaveToImage(ctx, info.ImageId, contactUuid)
|
||||||
|
return "Saved", nil
|
||||||
|
})
|
||||||
|
|
||||||
|
return agent, nil
|
||||||
|
}
|
@ -2,6 +2,7 @@ package agents
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"screenmark/screenmark/agents/client"
|
"screenmark/screenmark/agents/client"
|
||||||
"time"
|
"time"
|
||||||
@ -29,6 +30,9 @@ Use it when the image contains information relating a person.
|
|||||||
locationAgent
|
locationAgent
|
||||||
Use it when the image contains some address or a place.
|
Use it when the image contains some address or a place.
|
||||||
|
|
||||||
|
eventAgent
|
||||||
|
Use it when the image contains an event, this can be a date, a message suggesting an event.
|
||||||
|
|
||||||
noAction
|
noAction
|
||||||
When you think there is no more information to extract from the image.
|
When you think there is no more information to extract from the image.
|
||||||
|
|
||||||
@ -74,6 +78,18 @@ const OrchestratorTools = `
|
|||||||
"required": []
|
"required": []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "function",
|
||||||
|
"function": {
|
||||||
|
"name": "eventAgent",
|
||||||
|
"description": "Use when then image contains some event",
|
||||||
|
"parameters": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {},
|
||||||
|
"required": []
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "function",
|
"type": "function",
|
||||||
@ -99,7 +115,7 @@ type Status struct {
|
|||||||
Ok bool `json:"ok"`
|
Ok bool `json:"ok"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewOrchestratorAgent(noteAgent NoteAgent, contactAgent ContactAgent, locationAgent LocationAgent, imageName string, imageData []byte) (OrchestratorAgent, error) {
|
func NewOrchestratorAgent(noteAgent NoteAgent, contactAgent ContactAgent, locationAgent LocationAgent, eventAgent EventAgent, imageName string, imageData []byte) (OrchestratorAgent, error) {
|
||||||
agent, err := client.CreateAgentClient(log.NewWithOptions(os.Stdout, log.Options{
|
agent, err := client.CreateAgentClient(log.NewWithOptions(os.Stdout, log.Options{
|
||||||
ReportTimestamp: true,
|
ReportTimestamp: true,
|
||||||
TimeFormat: time.Kitchen,
|
TimeFormat: time.Kitchen,
|
||||||
@ -134,6 +150,14 @@ func NewOrchestratorAgent(noteAgent NoteAgent, contactAgent ContactAgent, locati
|
|||||||
}, nil
|
}, nil
|
||||||
})
|
})
|
||||||
|
|
||||||
|
agent.ToolHandler.AddTool("eventAgent", func(info client.ToolHandlerInfo, args string, call client.ToolCall) (any, error) {
|
||||||
|
go eventAgent.client.RunAgent(eventPrompt, eventTools, "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) {
|
agent.ToolHandler.AddTool("noAction", func(info client.ToolHandlerInfo, args string, call client.ToolCall) (any, error) {
|
||||||
// To nothing
|
// To nothing
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@ func ListenNewImageEvents(db *sql.DB, eventManager *EventManager) {
|
|||||||
defer listener.Close()
|
defer listener.Close()
|
||||||
|
|
||||||
locationModel := models.NewLocationModel(db)
|
locationModel := models.NewLocationModel(db)
|
||||||
|
eventModel := models.NewEventModel(db)
|
||||||
noteModel := models.NewNoteModel(db)
|
noteModel := models.NewNoteModel(db)
|
||||||
imageModel := models.NewImageModel(db)
|
imageModel := models.NewImageModel(db)
|
||||||
contactModel := models.NewContactModel(db)
|
contactModel := models.NewContactModel(db)
|
||||||
@ -56,6 +57,11 @@ func ListenNewImageEvents(db *sql.DB, eventManager *EventManager) {
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
eventAgent, err := agents.NewEventAgent(eventModel)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
image, err := imageModel.GetToProcessWithData(ctx, imageId)
|
image, err := imageModel.GetToProcessWithData(ctx, imageId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("Failed to GetToProcessWithData")
|
log.Println("Failed to GetToProcessWithData")
|
||||||
@ -69,7 +75,7 @@ func ListenNewImageEvents(db *sql.DB, eventManager *EventManager) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
orchestrator, err := agents.NewOrchestratorAgent(noteAgent, contactAgent, locationAgent, image.Image.ImageName, image.Image.Image)
|
orchestrator, err := agents.NewOrchestratorAgent(noteAgent, contactAgent, locationAgent, eventAgent, image.Image.ImageName, image.Image.Image)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,20 @@ type EventModel struct {
|
|||||||
dbPool *sql.DB
|
dbPool *sql.DB
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m EventModel) List(ctx context.Context, userId uuid.UUID) ([]model.Events, error) {
|
||||||
|
listEventsStmt := SELECT(Events.AllColumns).
|
||||||
|
FROM(
|
||||||
|
Events.
|
||||||
|
INNER_JOIN(UserEvents, UserEvents.EventID.EQ(Events.ID)),
|
||||||
|
).
|
||||||
|
WHERE(UserEvents.UserID.EQ(UUID(userId)))
|
||||||
|
|
||||||
|
events := []model.Events{}
|
||||||
|
|
||||||
|
err := listEventsStmt.QueryContext(ctx, m.dbPool, &events)
|
||||||
|
return events, err
|
||||||
|
}
|
||||||
|
|
||||||
func (m EventModel) Save(ctx context.Context, userId uuid.UUID, event model.Events) (model.Events, error) {
|
func (m EventModel) Save(ctx context.Context, userId uuid.UUID, event model.Events) (model.Events, error) {
|
||||||
// TODO tx here
|
// TODO tx here
|
||||||
insertEventStmt := Events.
|
insertEventStmt := Events.
|
||||||
|
Reference in New Issue
Block a user