package humantasks import ( "context" "fmt" "strings" "inbox/internal/base/timeutil" "inbox/internal/domain/humantask" "inbox/internal/domain/message" ) type Repository interface { GetHumanTask(ctx context.Context, taskID string) (humantask.Record, error) ListHumanTasksByTopic(ctx context.Context, topicID string) ([]humantask.Record, error) ListPendingHumanTasksByWorkspace(ctx context.Context, workspaceID string) ([]humantask.Record, error) GetMessage(ctx context.Context, messageID string) (message.Record, error) AnswerHumanTask(ctx context.Context, taskID string, reply message.Record) (humantask.Record, message.Record, error) } type Service struct { repo Repository clock timeutil.Clock } type AnswerResult struct { Task humantask.Record `json:"task"` Message message.Record `json:"message"` } func NewService(repo Repository, clock timeutil.Clock) *Service { if clock == nil { clock = timeutil.SystemClock{} } return &Service{repo: repo, clock: clock} } func (s *Service) ListByTopic(ctx context.Context, topicID string) ([]humantask.Record, error) { return s.repo.ListHumanTasksByTopic(ctx, topicID) } func (s *Service) ListPendingByWorkspace(ctx context.Context, workspaceID string) ([]humantask.Record, error) { return s.repo.ListPendingHumanTasksByWorkspace(ctx, workspaceID) } func (s *Service) Answer(ctx context.Context, taskID, bodyMarkdown string) (AnswerResult, error) { bodyMarkdown = strings.TrimSpace(bodyMarkdown) if bodyMarkdown == "" { return AnswerResult{}, fmt.Errorf("body markdown is required") } task, err := s.repo.GetHumanTask(ctx, taskID) if err != nil { return AnswerResult{}, err } prompt, err := s.repo.GetMessage(ctx, task.PromptMessageID) if err != nil { return AnswerResult{}, err } updatedTask, reply, err := s.repo.AnswerHumanTask(ctx, task.ID, message.Record{ WorkspaceID: task.WorkspaceID, TopicID: task.TopicID, FromRoleName: task.RoleName, ToExpr: prompt.FromRoleName, Type: message.TypeChat, Stage: prompt.Stage, ReplyToMessageID: prompt.ID, BodyMarkdown: bodyMarkdown, CreatedAt: timeutil.FormatRFC3339(s.clock.Now()), }) if err != nil { return AnswerResult{}, err } return AnswerResult{Task: updatedTask, Message: reply}, nil }