Files
jules/engine/processor.go
T

140 lines
3.3 KiB
Go

package engine
import (
"context"
"errors"
"time"
"github.com/d1nch8g/jules/chat"
"github.com/d1nch8g/jules/database"
"github.com/d1nch8g/jules/engine/actions"
"github.com/d1nch8g/jules/engine/prompt"
"github.com/d1nch8g/jules/engine/trace"
"github.com/d1nch8g/jules/engine/user"
)
func (e *Engine) defaultProcessMessage(ctx context.Context, msg chat.Message) {
span := trace.FromMessage(ctx, msg)
u, err := user.FromMessage(ctx, e.Database, msg, e.ActionLimit)
if err != nil {
span.Error("failed to get user from message", err)
return
}
span.User(u)
err = e.Database.Actions().Log(ctx, &database.Action{
UserID: u.ID,
ExecutedAt: time.Now(),
Payload: actions.Raw(actions.UserAction{
Type: "user_message",
Content: msg.Text,
}),
})
if err != nil {
span.Error("failed to record action", err)
return
}
e.process(ctx, span, u, msg.Chat, msg.Text)
}
func (e *Engine) defaultProcessNotification(ctx context.Context, notif database.Notification) {
span := trace.FromNotification(ctx, notif)
u, err := user.FromNotification(ctx, e.Database, notif, e.ActionLimit)
if err != nil {
span.Error("failed to get user from notificaion", err)
return
}
span.User(u)
err = e.Database.Actions().Log(ctx, &database.Action{
UserID: u.ID,
ExecutedAt: time.Now(),
Payload: actions.Raw(actions.UserAction{
Type: "activated_notificaion",
Content: notif.Content,
}),
})
if err != nil {
span.Error("failed to record action", err)
return
}
e.process(ctx, span, u, database.DatabaseSource, notif.Content)
}
func (e *Engine) process(ctx context.Context, span *trace.Span, user *user.User, source, content string) {
var errs []error
for range e.Parameters.LLMRetryAttempts {
p := prompt.Build(user, source, content, errs...)
ctx, cancel := context.WithTimeout(ctx, e.LLMResponseTimeout)
result, err := e.LLM.Process(ctx, p)
cancel()
if err != nil {
errs = append(errs, err)
span.LLMResponse(result)
span.Warn("failed to receive LLM response", errs...)
continue
}
actionSlice, err := actions.Parse(result, user.Timezone)
if err != nil {
errs = append(errs, err)
span.LLMResponse(result)
span.Warn("failed to parse actions received from LLM", errs...)
continue
}
runtime := &actions.Runtime{
User: user,
Database: e.Database,
Searcher: e.Searcher,
Chats: e.Chats,
}
var validationFailed bool
for _, action := range actionSlice {
err = action.Validate(ctx, runtime)
if err != nil {
errs = append(errs, err)
validationFailed = true
}
}
if validationFailed {
span.Actions(actionSlice)
span.Warn("failed to validate actions", errs...)
continue
}
for _, action := range actionSlice {
err = action.Execute(ctx, runtime)
if err != nil {
span.Actions(actionSlice)
errs = append(errs, err)
span.Warn("failed to execute actions", errs...)
}
err := e.Database.Actions().Log(ctx, &database.Action{
UserID: user.ID,
ExecutedAt: time.Now(),
Payload: actions.Raw(action),
})
if err != nil {
span.Actions(actionSlice)
errs = append(errs, err)
span.Warn("failed to record action", err)
}
}
span.Info("successfully processed")
return
}
span.Error("all attempts to process event have failed", errors.Join(errs...))
}