Files
ai-agent/internal/ai/runtime/reply_trigger_service.go
T
mlogclub c246b85a9e feat: add support for request ID tracking across services
- Implemented request ID handling in various services and handlers to improve traceability of requests.
- Added new AuthOptions endpoint to expose WxWork and OIDC configuration options.
- Updated message and event logging to include request ID for better debugging.
- Enhanced login form to dynamically show available authentication options based on server configuration.
- Introduced utility functions for normalizing and ensuring valid request IDs.
- Updated tests to verify request ID functionality in message sending and event logging.
2026-05-27 22:18:43 +08:00

117 lines
3.6 KiB
Go

package runtime
import (
"context"
"log/slog"
"strings"
"time"
applicationruntime "cs-agent/internal/ai/application/runtime"
"cs-agent/internal/models"
"cs-agent/internal/pkg/enums"
"cs-agent/internal/pkg/tracex"
svc "cs-agent/internal/services"
)
func (s *aiReplyService) resolveReplyTimeout(aiAgent models.AIAgent) time.Duration {
if aiAgent.ReplyTimeoutSeconds <= 0 {
return time.Duration(defaultAIReplyAsyncTimeoutSeconds) * time.Second
}
if aiAgent.ReplyTimeoutSeconds > maxAIReplyAsyncTimeoutSeconds {
return time.Duration(maxAIReplyAsyncTimeoutSeconds) * time.Second
}
return time.Duration(aiAgent.ReplyTimeoutSeconds) * time.Second
}
func (s *aiReplyService) TriggerReplyAsync(conversation models.Conversation, message models.Message) {
go func() {
aiAgent := svc.AIAgentService.Get(conversation.AIAgentID)
if aiAgent == nil || aiAgent.Status != enums.StatusOk {
return
}
startedAt := time.Now()
timeout := s.resolveReplyTimeout(*aiAgent)
ctx, cancel := context.WithTimeout(tracex.ContextWithRequestID(context.Background(), message.RequestID), timeout)
defer cancel()
if err := s.TriggerReply(ctx, conversation, message, *aiAgent); err != nil {
slog.Error("failed to trigger ai reply",
"requestId", message.RequestID,
"message_id", message.ID,
"timeout_ms", timeout.Milliseconds(),
"elapsed_ms", time.Since(startedAt).Milliseconds(),
"error", err)
}
}()
}
func (s *aiReplyService) TriggerReply(ctx context.Context, conversation models.Conversation, message models.Message, aiAgent models.AIAgent) (retErr error) {
startedAt := time.Now()
trace := &aiReplyTraceData{Status: "started"}
var summary *applicationruntime.Summary
replyCtx := aiReplyContext{
Conversation: conversation,
Message: message,
AIAgent: aiAgent,
Trace: trace,
SummaryRef: &summary,
}
if err := ctx.Err(); err != nil {
return err
}
if s.eligibility != nil && !s.eligibility.CanReply(conversation, message, aiAgent) {
return nil
}
defer func() {
s.runlog.Write(replyRunLogInput{
StartedAt: startedAt,
Message: message,
Conversation: conversation,
AIAgent: aiAgent,
Question: message.Content,
RunErr: retErr,
Trace: trace,
Summary: summary,
})
}()
if pendingInterrupt := svc.ConversationInterruptService.FindLatestPendingByConversationID(conversation.ID); pendingInterrupt != nil {
replyCtx.PendingInterrupt = pendingInterrupt
return s.resumePendingInterrupt(ctx, replyCtx)
}
return s.executeReply(ctx, replyCtx)
}
func (s *aiReplyService) resumePendingInterrupt(ctx context.Context, replyCtx aiReplyContext) error {
return s.interrupts.ResumePendingInterrupt(ctx, s, replyCtx)
}
func (s *aiReplyService) executeReply(ctx context.Context, replyCtx aiReplyContext) error {
summary, err := s.executor.Run(ctx, runtimeReplyRunInput{
Conversation: replyCtx.Conversation,
Message: replyCtx.Message,
AIAgent: replyCtx.AIAgent,
Trace: replyCtx.Trace,
})
replyCtx.setSummary(summary)
if err != nil {
return err
}
if summary != nil && summary.Interrupted {
return s.interrupts.HandleInterruptedSummary(s, replyCtx, summary)
}
if summary != nil && strings.TrimSpace(summary.ReplyText) != "" {
replyMessage, err := s.commit.CommitAIReply(replyCommitInput{
Conversation: replyCtx.Conversation,
Message: replyCtx.Message,
AIAgent: replyCtx.AIAgent,
ReplyText: summary.ReplyText,
Trace: replyCtx.Trace,
ClientPrefix: "ai_reply",
})
if err != nil {
return err
}
replyCtx.Trace.ReplySent = replyMessage != nil
}
return nil
}