tâches planifiées : prompts cron persistés, outil scheduler, conversations liées aux tâches, rattrapage des exécutions manquées au redémarrage (go-cron MissedRunOnce)
This commit is contained in:
1 parent
bedb6c98e7
commit
058370830f
71 files changed
+1627
-100
No files matched your search
@@ -47,6 +47,7 @@ func (s *Service) NewChat(
|
||||
userID string,
|
||||
teamID string,
|
||||
agentID string,
|
||||
taskID string,
|
||||
) (*domain.Chat, error) {
|
||||
|
||||
team, err := s.repoUser.FindTeam(userID, teamID)
|
||||
@@ -60,6 +61,7 @@ func (s *Service) NewChat(
|
||||
UserID: userID,
|
||||
AgentID: agentID,
|
||||
TeamID: team.ID,
|
||||
TaskID: taskID,
|
||||
StartDatetime: &start,
|
||||
Title: "Nouvelle conversation",
|
||||
}
|
||||
@@ -170,8 +172,8 @@ func (s *Service) AddChatMessage(
|
||||
return message, nil
|
||||
}
|
||||
|
||||
func (s *Service) ListChats(userID string, teamID string, page int, query string) ([]*domain.Chat, error) {
|
||||
return s.repoChat.ListChats(userID, teamID, page, query)
|
||||
func (s *Service) ListChats(userID string, teamID string, page int, query string, taskID string) ([]*domain.Chat, error) {
|
||||
return s.repoChat.ListChats(userID, teamID, page, query, taskID)
|
||||
}
|
||||
|
||||
func (s *Service) GetChat(userID string, teamID, chatID string) (*domain.Chat, error) {
|
||||
|
||||
@@ -3,6 +3,7 @@ package chat
|
||||
import (
|
||||
"context"
|
||||
_ "embed"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"sync"
|
||||
|
||||
@@ -87,43 +88,69 @@ func (s *ChatSession) run(ctx context.Context) error {
|
||||
for _, tc := range msg.ToolCalls {
|
||||
|
||||
toolImpl := s.toolService.GetToolImpl(tc.Function.Name)
|
||||
slog.Info("Execute tool", "name", tc.Function.Name, "impl", toolImpl)
|
||||
toolRecord, err := s.toolService.GetToolByName(s.userID, s.teamID, toolImpl.Name())
|
||||
if err != nil {
|
||||
slog.Info("Execute tool", "error", err)
|
||||
toolResponse := &domain.Message{
|
||||
ChatID: s.chatID,
|
||||
TeamID: s.teamID,
|
||||
ToolCallID: tc.ID,
|
||||
Role: string(domain.RoleTool),
|
||||
Content: "ERROR: " + err.Error(),
|
||||
var toolRecord *domain.Tool
|
||||
var executeErr error
|
||||
if toolImpl == nil {
|
||||
executeErr = fmt.Errorf("unknown tool %s", tc.Function.Name)
|
||||
slog.Info("Execute tool", "error", executeErr)
|
||||
} else {
|
||||
slog.Info("Execute tool", "name", tc.Function.Name, "impl", toolImpl)
|
||||
var err error
|
||||
toolRecord, err = s.toolService.GetToolByName(s.userID, s.teamID, toolImpl.Name())
|
||||
if err != nil {
|
||||
// l'outil n'est pas encore enregistré pour l'équipe :
|
||||
// auto-enregistrement (comme le fait la liste des outils)
|
||||
toolRecord, err = s.toolService.CreateTool(s.userID, &domain.Tool{
|
||||
TeamID: s.teamID,
|
||||
Name: toolImpl.Name(),
|
||||
Enabled: true,
|
||||
})
|
||||
}
|
||||
if err != nil {
|
||||
executeErr = err
|
||||
slog.Info("Execute tool", "error", err)
|
||||
}
|
||||
s.repoChat.CreateChatMessage(s.userID, toolResponse)
|
||||
}
|
||||
output, err := toolImpl.Execute(ctx, []byte(tc.Function.Arguments), toolRecord.Configuration)
|
||||
|
||||
var toolResponse *domain.Message
|
||||
if err != nil {
|
||||
if executeErr != nil {
|
||||
toolResponse = &domain.Message{
|
||||
ChatID: s.chatID,
|
||||
TeamID: s.teamID,
|
||||
ToolCallID: tc.ID,
|
||||
Role: string(domain.RoleTool),
|
||||
Content: "ERROR: " + err.Error(),
|
||||
Content: "ERROR: " + executeErr.Error(),
|
||||
}
|
||||
} else {
|
||||
toolResponse = &domain.Message{
|
||||
ChatID: s.chatID,
|
||||
TeamID: s.teamID,
|
||||
ToolCallID: tc.ID,
|
||||
Role: string(domain.RoleTool),
|
||||
Content: string(output),
|
||||
var output []byte
|
||||
output, executeErr = toolImpl.Execute(
|
||||
domain.WithToolContext(ctx, s.userID, s.teamID, s.modelID),
|
||||
[]byte(tc.Function.Arguments),
|
||||
toolRecord.Configuration,
|
||||
)
|
||||
if executeErr != nil {
|
||||
toolResponse = &domain.Message{
|
||||
ChatID: s.chatID,
|
||||
TeamID: s.teamID,
|
||||
ToolCallID: tc.ID,
|
||||
Role: string(domain.RoleTool),
|
||||
Content: "ERROR: " + executeErr.Error(),
|
||||
}
|
||||
} else {
|
||||
toolResponse = &domain.Message{
|
||||
ChatID: s.chatID,
|
||||
TeamID: s.teamID,
|
||||
ToolCallID: tc.ID,
|
||||
Role: string(domain.RoleTool),
|
||||
Content: string(output),
|
||||
}
|
||||
}
|
||||
}
|
||||
toolResponse, err = s.repoChat.CreateChatMessage(s.userID, toolResponse)
|
||||
persisted, err := s.repoChat.CreateChatMessage(s.userID, toolResponse)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.messages = append(s.messages, toolResponse)
|
||||
s.messages = append(s.messages, persisted)
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
@@ -25,3 +25,7 @@ Never present a partial result as complete. If, despite your efforts, you cannot
|
||||
Use the available tools and skills whenever they can help you answer more accurately, verify a fact, or complete the task. Don't answer from memory when a tool can provide the answer. If several tools are relevant, combine them. When a task matches an available skill, consult it before starting.
|
||||
|
||||
You may skip them for purely conversational exchanges or questions whose answer depends on no information that needs verifying.
|
||||
|
||||
## Scheduled tasks
|
||||
|
||||
When the user asks to perform something later or on a schedule ("do this every day at 8am", "tomorrow morning give me...", "every Monday summarize..."), actually schedule it with the scheduler tool instead of just promising. Translate the request into a cron spec (5 fields: minute hour day-of-month month day-of-week; e.g. "0 8 * * *" is 8am every day). Set repeat=false for one-shot requests. The prompt you schedule must be fully self-contained: it will run in a fresh conversation with no memory of the current one.
|
||||
Reference in new issue
Block a user