refactor: remove trace data from reply context and related services
This commit is contained in:
@@ -21,7 +21,6 @@ type replyCommitInput struct {
|
|||||||
Message models.Message
|
Message models.Message
|
||||||
AIAgent models.AIAgent
|
AIAgent models.AIAgent
|
||||||
ReplyText string
|
ReplyText string
|
||||||
Trace *aiReplyTraceData
|
|
||||||
ClientPrefix string
|
ClientPrefix string
|
||||||
IncrementRound bool
|
IncrementRound bool
|
||||||
}
|
}
|
||||||
@@ -35,7 +34,6 @@ func (s *replyCommitService) SendAIReply(input replyCommitInput) (*models.Messag
|
|||||||
if replyText == "" {
|
if replyText == "" {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
commitStartedAt := time.Now()
|
|
||||||
replyMessage, err := svc.MessageService.SendAIMessageWithRequestID(
|
replyMessage, err := svc.MessageService.SendAIMessageWithRequestID(
|
||||||
input.Conversation.ID,
|
input.Conversation.ID,
|
||||||
input.AIAgent.ID,
|
input.AIAgent.ID,
|
||||||
@@ -46,13 +44,6 @@ func (s *replyCommitService) SendAIReply(input replyCommitInput) (*models.Messag
|
|||||||
s.buildAIPrincipal(input.AIAgent),
|
s.buildAIPrincipal(input.AIAgent),
|
||||||
input.Message.RequestID,
|
input.Message.RequestID,
|
||||||
)
|
)
|
||||||
if input.Trace != nil {
|
|
||||||
input.Trace.CommitMs = time.Since(commitStartedAt).Milliseconds()
|
|
||||||
input.Trace.ReplySent = err == nil && replyMessage != nil
|
|
||||||
if replyMessage != nil {
|
|
||||||
input.Trace.ReplyMessageID = replyMessage.ID
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err != nil || !input.IncrementRound {
|
if err != nil || !input.IncrementRound {
|
||||||
return replyMessage, err
|
return replyMessage, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ type aiReplyContext struct {
|
|||||||
Conversation models.Conversation
|
Conversation models.Conversation
|
||||||
Message models.Message
|
Message models.Message
|
||||||
AIAgent models.AIAgent
|
AIAgent models.AIAgent
|
||||||
Trace *aiReplyTraceData
|
|
||||||
SummaryRef **applicationruntime.Summary
|
SummaryRef **applicationruntime.Summary
|
||||||
PendingInterrupt *models.ConversationInterrupt
|
PendingInterrupt *models.ConversationInterrupt
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,18 +8,6 @@ import (
|
|||||||
"agent-desk/internal/pkg/toolx"
|
"agent-desk/internal/pkg/toolx"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestRuntimeTraceFinalAction(t *testing.T) {
|
|
||||||
if got := runtimeTraceFinalAction(&applicationruntime.Summary{Status: "completed", ReplyText: "ok"}); got != "reply" {
|
|
||||||
t.Fatalf("expected reply final action, got %q", got)
|
|
||||||
}
|
|
||||||
if got := runtimeTraceFinalAction(&applicationruntime.Summary{Status: "completed"}); got != "completed" {
|
|
||||||
t.Fatalf("expected completed final action, got %q", got)
|
|
||||||
}
|
|
||||||
if got := runtimeTraceFinalAction(&applicationruntime.Summary{Status: "fallback"}); got != "fallback" {
|
|
||||||
t.Fatalf("expected fallback final action, got %q", got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestExtractRuntimeToolTraces(t *testing.T) {
|
func TestExtractRuntimeToolTraces(t *testing.T) {
|
||||||
summary := &applicationruntime.Summary{
|
summary := &applicationruntime.Summary{
|
||||||
TraceData: `{
|
TraceData: `{
|
||||||
|
|||||||
@@ -25,21 +25,17 @@ func (s *replyInterruptService) ResumePendingInterrupt(ctx context.Context, owne
|
|||||||
Message: replyCtx.Message,
|
Message: replyCtx.Message,
|
||||||
AIAgent: replyCtx.AIAgent,
|
AIAgent: replyCtx.AIAgent,
|
||||||
PendingInterrupt: replyCtx.PendingInterrupt,
|
PendingInterrupt: replyCtx.PendingInterrupt,
|
||||||
Trace: replyCtx.Trace,
|
|
||||||
})
|
})
|
||||||
replyCtx.setSummary(summary)
|
replyCtx.setSummary(summary)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if isCheckpointMissingError(err) {
|
if isCheckpointMissingError(err) {
|
||||||
summary = expiredInterruptSummary()
|
summary = expiredInterruptSummary()
|
||||||
replyCtx.setSummary(summary)
|
replyCtx.setSummary(summary)
|
||||||
replyCtx.Trace.Status = "interrupt_expired"
|
|
||||||
replyCtx.Trace.FinalAction = "expired"
|
|
||||||
replyMessage, expireErr := owner.commit.CommitAIReply(replyCommitInput{
|
replyMessage, expireErr := owner.commit.CommitAIReply(replyCommitInput{
|
||||||
Conversation: replyCtx.Conversation,
|
Conversation: replyCtx.Conversation,
|
||||||
Message: replyCtx.Message,
|
Message: replyCtx.Message,
|
||||||
AIAgent: replyCtx.AIAgent,
|
AIAgent: replyCtx.AIAgent,
|
||||||
ReplyText: summary.ReplyText,
|
ReplyText: summary.ReplyText,
|
||||||
Trace: replyCtx.Trace,
|
|
||||||
ClientPrefix: "ai_interrupt_expired",
|
ClientPrefix: "ai_interrupt_expired",
|
||||||
})
|
})
|
||||||
if expireErr != nil {
|
if expireErr != nil {
|
||||||
@@ -65,7 +61,6 @@ func (s *replyInterruptService) ResumePendingInterrupt(ctx context.Context, owne
|
|||||||
Message: replyCtx.Message,
|
Message: replyCtx.Message,
|
||||||
AIAgent: replyCtx.AIAgent,
|
AIAgent: replyCtx.AIAgent,
|
||||||
ReplyText: summary.ReplyText,
|
ReplyText: summary.ReplyText,
|
||||||
Trace: replyCtx.Trace,
|
|
||||||
ClientPrefix: "ai_resume",
|
ClientPrefix: "ai_resume",
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -95,7 +90,6 @@ func (s *replyInterruptService) HandleInterruptedSummary(owner *aiReplyService,
|
|||||||
Message: replyCtx.Message,
|
Message: replyCtx.Message,
|
||||||
AIAgent: replyCtx.AIAgent,
|
AIAgent: replyCtx.AIAgent,
|
||||||
ReplyText: replyText,
|
ReplyText: replyText,
|
||||||
Trace: replyCtx.Trace,
|
|
||||||
ClientPrefix: "ai_interrupt",
|
ClientPrefix: "ai_interrupt",
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -117,7 +111,6 @@ func (s *replyInterruptService) HandleInterruptedResume(owner *aiReplyService, r
|
|||||||
Message: replyCtx.Message,
|
Message: replyCtx.Message,
|
||||||
AIAgent: replyCtx.AIAgent,
|
AIAgent: replyCtx.AIAgent,
|
||||||
ReplyText: replyText,
|
ReplyText: replyText,
|
||||||
Trace: replyCtx.Trace,
|
|
||||||
ClientPrefix: "ai_interrupt_resume",
|
ClientPrefix: "ai_interrupt_resume",
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -45,13 +45,11 @@ func (s *aiReplyService) TriggerReplyAsync(conversation models.Conversation, mes
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *aiReplyService) TriggerReply(ctx context.Context, conversation models.Conversation, message models.Message, aiAgent models.AIAgent) (retErr error) {
|
func (s *aiReplyService) TriggerReply(ctx context.Context, conversation models.Conversation, message models.Message, aiAgent models.AIAgent) (retErr error) {
|
||||||
trace := &aiReplyTraceData{Status: "started"}
|
|
||||||
var summary *applicationruntime.Summary
|
var summary *applicationruntime.Summary
|
||||||
replyCtx := aiReplyContext{
|
replyCtx := aiReplyContext{
|
||||||
Conversation: conversation,
|
Conversation: conversation,
|
||||||
Message: message,
|
Message: message,
|
||||||
AIAgent: aiAgent,
|
AIAgent: aiAgent,
|
||||||
Trace: trace,
|
|
||||||
SummaryRef: &summary,
|
SummaryRef: &summary,
|
||||||
}
|
}
|
||||||
if err := ctx.Err(); err != nil {
|
if err := ctx.Err(); err != nil {
|
||||||
@@ -76,7 +74,6 @@ func (s *aiReplyService) executeReply(ctx context.Context, replyCtx aiReplyConte
|
|||||||
Conversation: replyCtx.Conversation,
|
Conversation: replyCtx.Conversation,
|
||||||
Message: replyCtx.Message,
|
Message: replyCtx.Message,
|
||||||
AIAgent: replyCtx.AIAgent,
|
AIAgent: replyCtx.AIAgent,
|
||||||
Trace: replyCtx.Trace,
|
|
||||||
})
|
})
|
||||||
replyCtx.setSummary(summary)
|
replyCtx.setSummary(summary)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -86,18 +83,16 @@ func (s *aiReplyService) executeReply(ctx context.Context, replyCtx aiReplyConte
|
|||||||
return s.interrupts.HandleInterruptedSummary(s, replyCtx, summary)
|
return s.interrupts.HandleInterruptedSummary(s, replyCtx, summary)
|
||||||
}
|
}
|
||||||
if summary != nil && strings.TrimSpace(summary.ReplyText) != "" {
|
if summary != nil && strings.TrimSpace(summary.ReplyText) != "" {
|
||||||
replyMessage, err := s.commit.CommitAIReply(replyCommitInput{
|
_, err := s.commit.CommitAIReply(replyCommitInput{
|
||||||
Conversation: replyCtx.Conversation,
|
Conversation: replyCtx.Conversation,
|
||||||
Message: replyCtx.Message,
|
Message: replyCtx.Message,
|
||||||
AIAgent: replyCtx.AIAgent,
|
AIAgent: replyCtx.AIAgent,
|
||||||
ReplyText: summary.ReplyText,
|
ReplyText: summary.ReplyText,
|
||||||
Trace: replyCtx.Trace,
|
|
||||||
ClientPrefix: "ai_reply",
|
ClientPrefix: "ai_reply",
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
replyCtx.Trace.ReplySent = replyMessage != nil
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +1,5 @@
|
|||||||
package runtime
|
package runtime
|
||||||
|
|
||||||
import "encoding/json"
|
|
||||||
|
|
||||||
type aiReplyTraceData struct {
|
|
||||||
Status string `json:"status"`
|
|
||||||
RuntimeLatencyMs int64 `json:"runtimeLatencyMs,omitempty"`
|
|
||||||
RecheckMs int64 `json:"recheckMs,omitempty"`
|
|
||||||
CommitMs int64 `json:"commitMs,omitempty"`
|
|
||||||
FinalAction string `json:"finalAction,omitempty"`
|
|
||||||
ResumeSource string `json:"resumeSource,omitempty"`
|
|
||||||
ReplySent bool `json:"replySent,omitempty"`
|
|
||||||
ReplyMessageID int64 `json:"replyMessageId,omitempty"`
|
|
||||||
Runtime json.RawMessage `json:"runtime,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
defaultAIReplyAsyncTimeoutSeconds = 180
|
defaultAIReplyAsyncTimeoutSeconds = 180
|
||||||
maxAIReplyAsyncTimeoutSeconds = 600
|
maxAIReplyAsyncTimeoutSeconds = 600
|
||||||
|
|||||||
@@ -2,10 +2,8 @@ package runtime
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
|
|
||||||
applicationruntime "agent-desk/internal/ai/application/runtime"
|
applicationruntime "agent-desk/internal/ai/application/runtime"
|
||||||
"agent-desk/internal/ai/runtime/graphs"
|
"agent-desk/internal/ai/runtime/graphs"
|
||||||
@@ -19,7 +17,6 @@ type runtimeReplyRunInput struct {
|
|||||||
Conversation models.Conversation
|
Conversation models.Conversation
|
||||||
Message models.Message
|
Message models.Message
|
||||||
AIAgent models.AIAgent
|
AIAgent models.AIAgent
|
||||||
Trace *aiReplyTraceData
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type runtimeReplyResumeInput struct {
|
type runtimeReplyResumeInput struct {
|
||||||
@@ -27,7 +24,6 @@ type runtimeReplyResumeInput struct {
|
|||||||
Message models.Message
|
Message models.Message
|
||||||
AIAgent models.AIAgent
|
AIAgent models.AIAgent
|
||||||
PendingInterrupt *models.ConversationInterrupt
|
PendingInterrupt *models.ConversationInterrupt
|
||||||
Trace *aiReplyTraceData
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func newRuntimeReplyExecutor() *runtimeReplyExecutor {
|
func newRuntimeReplyExecutor() *runtimeReplyExecutor {
|
||||||
@@ -39,17 +35,12 @@ func (e *runtimeReplyExecutor) Run(ctx context.Context, input runtimeReplyRunInp
|
|||||||
if aiConfig == nil {
|
if aiConfig == nil {
|
||||||
return nil, fmt.Errorf("ai config is nil")
|
return nil, fmt.Errorf("ai config is nil")
|
||||||
}
|
}
|
||||||
runtimeStartedAt := time.Now()
|
|
||||||
summary, err := Service.Run(ctx, applicationruntime.Request{
|
summary, err := Service.Run(ctx, applicationruntime.Request{
|
||||||
Conversation: input.Conversation,
|
Conversation: input.Conversation,
|
||||||
UserMessage: input.Message,
|
UserMessage: input.Message,
|
||||||
AIAgent: input.AIAgent,
|
AIAgent: input.AIAgent,
|
||||||
AIConfig: *aiConfig,
|
AIConfig: *aiConfig,
|
||||||
})
|
})
|
||||||
if input.Trace != nil {
|
|
||||||
input.Trace.RuntimeLatencyMs = time.Since(runtimeStartedAt).Milliseconds()
|
|
||||||
e.fillTraceFromSummary(input.Trace, summary, err)
|
|
||||||
}
|
|
||||||
return summary, err
|
return summary, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,10 +52,6 @@ func (e *runtimeReplyExecutor) ResumePendingInterrupt(ctx context.Context, input
|
|||||||
if aiConfig == nil {
|
if aiConfig == nil {
|
||||||
return nil, fmt.Errorf("ai config is nil")
|
return nil, fmt.Errorf("ai config is nil")
|
||||||
}
|
}
|
||||||
runtimeStartedAt := time.Now()
|
|
||||||
if input.Trace != nil {
|
|
||||||
input.Trace.ResumeSource = "pending_interrupt"
|
|
||||||
}
|
|
||||||
summary, err := Service.Resume(ctx, applicationruntime.ResumeRequest{
|
summary, err := Service.Resume(ctx, applicationruntime.ResumeRequest{
|
||||||
Conversation: input.Conversation,
|
Conversation: input.Conversation,
|
||||||
UserMessage: input.Message,
|
UserMessage: input.Message,
|
||||||
@@ -75,32 +62,9 @@ func (e *runtimeReplyExecutor) ResumePendingInterrupt(ctx context.Context, input
|
|||||||
strings.TrimSpace(input.PendingInterrupt.InterruptID): strings.TrimSpace(input.Message.Content),
|
strings.TrimSpace(input.PendingInterrupt.InterruptID): strings.TrimSpace(input.Message.Content),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
if input.Trace != nil {
|
|
||||||
input.Trace.RuntimeLatencyMs = time.Since(runtimeStartedAt).Milliseconds()
|
|
||||||
e.fillTraceFromSummary(input.Trace, summary, err)
|
|
||||||
}
|
|
||||||
return summary, err
|
return summary, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *runtimeReplyExecutor) fillTraceFromSummary(trace *aiReplyTraceData, summary *applicationruntime.Summary, runErr error) {
|
|
||||||
if trace == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if runErr != nil {
|
|
||||||
trace.Status = "runtime_error"
|
|
||||||
trace.FinalAction = "error"
|
|
||||||
if summary != nil {
|
|
||||||
trace.Runtime = json.RawMessage(summary.TraceData)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
trace.Status = "runtime_prepared"
|
|
||||||
trace.FinalAction = runtimeTraceFinalAction(summary)
|
|
||||||
if summary != nil && strings.TrimSpace(summary.TraceData) != "" {
|
|
||||||
trace.Runtime = json.RawMessage(summary.TraceData)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func expiredInterruptSummary() *applicationruntime.Summary {
|
func expiredInterruptSummary() *applicationruntime.Summary {
|
||||||
return &applicationruntime.Summary{
|
return &applicationruntime.Summary{
|
||||||
Status: "expired",
|
Status: "expired",
|
||||||
|
|||||||
@@ -7,29 +7,6 @@ import (
|
|||||||
applicationruntime "agent-desk/internal/ai/application/runtime"
|
applicationruntime "agent-desk/internal/ai/application/runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
func runtimeTraceFinalAction(summary *applicationruntime.Summary) string {
|
|
||||||
if summary == nil {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
switch strings.TrimSpace(summary.Status) {
|
|
||||||
case "completed":
|
|
||||||
if strings.TrimSpace(summary.ReplyText) != "" {
|
|
||||||
return "reply"
|
|
||||||
}
|
|
||||||
return "completed"
|
|
||||||
case "fallback":
|
|
||||||
return "fallback"
|
|
||||||
case "error":
|
|
||||||
return "error"
|
|
||||||
case "interrupted":
|
|
||||||
return "interrupted"
|
|
||||||
case "expired":
|
|
||||||
return "expired"
|
|
||||||
default:
|
|
||||||
return strings.TrimSpace(summary.Status)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func extractToolSearchTrace(summary *applicationruntime.Summary) string {
|
func extractToolSearchTrace(summary *applicationruntime.Summary) string {
|
||||||
if summary == nil {
|
if summary == nil {
|
||||||
return ""
|
return ""
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ error.e0009: "AI configuration not found."
|
|||||||
error.e0010: "Select an AI configuration."
|
error.e0010: "Select an AI configuration."
|
||||||
error.e0011: "The AI configuration is not enabled."
|
error.e0011: "The AI configuration is not enabled."
|
||||||
error.e0012: "AI configuration not found."
|
error.e0012: "AI configuration not found."
|
||||||
error.e0013: "Agent run log not found."
|
|
||||||
error.e0014: "Checkpoint not found."
|
error.e0014: "Checkpoint not found."
|
||||||
error.e0015: "The checkpoint does not belong to this AI Agent."
|
error.e0015: "The checkpoint does not belong to this AI Agent."
|
||||||
error.e0016: "Direct Tool toolCode does not match serverCode."
|
error.e0016: "Direct Tool toolCode does not match serverCode."
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ error.e0009: "AI 配置不存在"
|
|||||||
error.e0010: "AI 配置不能为空"
|
error.e0010: "AI 配置不能为空"
|
||||||
error.e0011: "AI 配置未启用"
|
error.e0011: "AI 配置未启用"
|
||||||
error.e0012: "AI配置不存在"
|
error.e0012: "AI配置不存在"
|
||||||
error.e0013: "Agent 运行日志不存在"
|
|
||||||
error.e0014: "CheckPoint 不存在"
|
error.e0014: "CheckPoint 不存在"
|
||||||
error.e0015: "CheckPoint 与 AI Agent 不匹配"
|
error.e0015: "CheckPoint 与 AI Agent 不匹配"
|
||||||
error.e0016: "Direct Tool 的 toolCode 与 serverCode 不一致"
|
error.e0016: "Direct Tool 的 toolCode 与 serverCode 不一致"
|
||||||
|
|||||||
Reference in New Issue
Block a user