From 023ba802e4700a008546051a2dee76f50e0e94f7 Mon Sep 17 00:00:00 2001 From: mlogclub Date: Fri, 10 Apr 2026 16:23:25 +0800 Subject: [PATCH] feat: add Graph Tool code and handoff reason to agent run log model and related components --- internal/ai/runtime/reply_service.go | 20 ++++++++++- internal/builders/agent_run_log_builder.go | 2 ++ .../console/agent_run_log_controller.go | 5 +++ internal/models/models.go | 2 ++ internal/pkg/dto/response/skill_response.go | 2 ++ web/app/(console)/agent-run-logs/page.tsx | 34 +++++++++++++++++-- web/lib/api/admin.ts | 2 ++ 7 files changed, 64 insertions(+), 3 deletions(-) diff --git a/internal/ai/runtime/reply_service.go b/internal/ai/runtime/reply_service.go index 493fe70..8501433 100644 --- a/internal/ai/runtime/reply_service.go +++ b/internal/ai/runtime/reply_service.go @@ -309,6 +309,8 @@ func (s *aiReplyService) writeRunLog(startedAt time.Time, message models.Message SkillRouteTrace: strings.TrimSpace(summarySkillRouteTrace(summary)), ToolSearchTrace: extractToolSearchTrace(summary), GraphToolTrace: extractGraphToolTrace(summary), + GraphToolCode: firstGraphToolCode(summary), + HandoffReason: extractHandoffReason(summary), PlannedToolCode: plannedToolCode, PlanReason: planReason, InterruptType: firstInterruptType(summary), @@ -597,6 +599,21 @@ func firstGraphToolCode(summary *Summary) string { return "" } +func extractHandoffReason(summary *Summary) string { + trace := parseRuntimeTraceData(summary.TraceData) + for _, item := range trace.GraphTools.Items { + if strings.TrimSpace(item.ToolCode) != toolx.GraphHandoffConversationToolCode { + continue + } + if len(item.Arguments) == 0 { + return "" + } + reason, _ := item.Arguments["reason"].(string) + return strings.TrimSpace(reason) + } + return "" +} + type runtimeTraceProjection struct { ToolSearch struct { Raw json.RawMessage `json:"-"` @@ -608,7 +625,8 @@ type runtimeTraceProjection struct { GraphTools struct { Raw json.RawMessage `json:"-"` Items []struct { - ToolCode string `json:"toolCode"` + ToolCode string `json:"toolCode"` + Arguments map[string]any `json:"arguments"` } `json:"items"` } `json:"graphTools"` } diff --git a/internal/builders/agent_run_log_builder.go b/internal/builders/agent_run_log_builder.go index ed5ec4e..45fda25 100644 --- a/internal/builders/agent_run_log_builder.go +++ b/internal/builders/agent_run_log_builder.go @@ -22,6 +22,8 @@ func BuildAgentRunLog(item *models.AgentRunLog) response.AgentRunLogResponse { SkillRouteTrace: item.SkillRouteTrace, ToolSearchTrace: item.ToolSearchTrace, GraphToolTrace: item.GraphToolTrace, + GraphToolCode: item.GraphToolCode, + HandoffReason: item.HandoffReason, PlannedToolCode: item.PlannedToolCode, PlanReason: item.PlanReason, InterruptType: item.InterruptType, diff --git a/internal/controllers/console/agent_run_log_controller.go b/internal/controllers/console/agent_run_log_controller.go index 85eca19..c1a815b 100644 --- a/internal/controllers/console/agent_run_log_controller.go +++ b/internal/controllers/console/agent_run_log_controller.go @@ -26,6 +26,11 @@ func (c *AgentRunLogController) AnyList() *web.JsonResult { params.QueryFilter{ParamName: "aiAgentId"}, params.QueryFilter{ParamName: "plannedAction"}, params.QueryFilter{ParamName: "plannedSkillCode", Op: params.Like}, + params.QueryFilter{ParamName: "graphToolCode"}, + params.QueryFilter{ParamName: "interruptType"}, + params.QueryFilter{ParamName: "resumeSource"}, + params.QueryFilter{ParamName: "finalStatus"}, + params.QueryFilter{ParamName: "handoffReason", Op: params.Like}, params.QueryFilter{ParamName: "finalAction"}, params.QueryFilter{ParamName: "userMessage", Op: params.Like}, ).Desc("id") diff --git a/internal/models/models.go b/internal/models/models.go index 972c924..49881be 100644 --- a/internal/models/models.go +++ b/internal/models/models.go @@ -952,6 +952,8 @@ type AgentRunLog struct { SkillRouteTrace string `gorm:"type:text"` ToolSearchTrace string `gorm:"type:text"` GraphToolTrace string `gorm:"type:text"` + GraphToolCode string `gorm:"type:varchar(200);not null;default:'';index"` + HandoffReason string `gorm:"type:varchar(500);not null;default:''"` PlannedToolCode string `gorm:"type:varchar(200);not null;default:'';index"` PlanReason string `gorm:"type:varchar(500);not null;default:''"` InterruptType string `gorm:"type:varchar(50);not null;default:'';index"` diff --git a/internal/pkg/dto/response/skill_response.go b/internal/pkg/dto/response/skill_response.go index 456fa0f..a710b98 100644 --- a/internal/pkg/dto/response/skill_response.go +++ b/internal/pkg/dto/response/skill_response.go @@ -50,6 +50,8 @@ type AgentRunLogResponse struct { SkillRouteTrace string `json:"skillRouteTrace"` ToolSearchTrace string `json:"toolSearchTrace"` GraphToolTrace string `json:"graphToolTrace"` + GraphToolCode string `json:"graphToolCode"` + HandoffReason string `json:"handoffReason"` PlannedToolCode string `json:"plannedToolCode"` PlanReason string `json:"planReason"` InterruptType string `json:"interruptType"` diff --git a/web/app/(console)/agent-run-logs/page.tsx b/web/app/(console)/agent-run-logs/page.tsx index 935ab39..7ab8450 100644 --- a/web/app/(console)/agent-run-logs/page.tsx +++ b/web/app/(console)/agent-run-logs/page.tsx @@ -51,6 +51,15 @@ const actionOptions = [ { value: "fallback", label: "兜底" }, ] +const finalStatusOptions = [ + { value: "all", label: "全部状态" }, + { value: "completed", label: "completed" }, + { value: "interrupted", label: "interrupted" }, + { value: "expired", label: "expired" }, + { value: "error", label: "error" }, + { value: "fallback", label: "fallback" }, +] + function actionBadgeVariant(action: string) { switch (action) { case "handoff": @@ -74,10 +83,12 @@ export default function DashboardAgentRunLogsPage() { const [keywordInput, setKeywordInput] = useState("") const [plannedActionInput, setPlannedActionInput] = useState("all") const [finalActionInput, setFinalActionInput] = useState("all") + const [finalStatusInput, setFinalStatusInput] = useState("all") const [aiAgentIdInput, setAiAgentIdInput] = useState("all") const [keyword, setKeyword] = useState("") const [plannedAction, setPlannedAction] = useState("all") const [finalAction, setFinalAction] = useState("all") + const [finalStatus, setFinalStatus] = useState("all") const [aiAgentId, setAiAgentId] = useState("all") const [page, setPage] = useState(1) const [limit, setLimit] = useState(20) @@ -121,6 +132,7 @@ export default function DashboardAgentRunLogsPage() { userMessage: keyword.trim() || undefined, plannedAction: plannedAction === "all" ? undefined : plannedAction, finalAction: finalAction === "all" ? undefined : finalAction, + finalStatus: finalStatus === "all" ? undefined : finalStatus, aiAgentId: aiAgentId === "all" ? undefined : aiAgentId, page, limit, @@ -131,7 +143,7 @@ export default function DashboardAgentRunLogsPage() { } finally { setLoading(false) } - }, [aiAgentId, finalAction, keyword, limit, page, plannedAction]) + }, [aiAgentId, finalAction, finalStatus, keyword, limit, page, plannedAction]) useEffect(() => { void loadData() @@ -153,6 +165,7 @@ export default function DashboardAgentRunLogsPage() { setKeyword(keywordInput) setPlannedAction(plannedActionInput) setFinalAction(finalActionInput) + setFinalStatus(finalStatusInput) setAiAgentId(aiAgentIdInput) setPage(1) } @@ -213,6 +226,16 @@ export default function DashboardAgentRunLogsPage() { onChange={(value) => setFinalActionInput(value || "all")} /> +
+ setFinalStatusInput(value || "all")} + /> +
- {item.plannedSkillCode || item.plannedToolCode} + {item.plannedSkillCode || item.graphToolCode || item.plannedToolCode} {item.plannedSkillName ? (
{item.plannedSkillName}
) : null} + {item.handoffReason ? ( +
+ 转人工原因:{item.handoffReason} +
+ ) : null}
) : ( "-" @@ -366,8 +394,10 @@ export default function DashboardAgentRunLogsPage() { `plannedAction: ${activeLog.plannedAction || "-"}`, `plannedSkillCode: ${activeLog.plannedSkillCode || "-"}`, `plannedSkillName: ${activeLog.plannedSkillName || "-"}`, + `graphToolCode: ${activeLog.graphToolCode || "-"}`, `plannedToolCode: ${activeLog.plannedToolCode || "-"}`, `planReason: ${activeLog.planReason || "-"}`, + `handoffReason: ${activeLog.handoffReason || "-"}`, `skillRouteTrace: ${activeLog.skillRouteTrace || "-"}`, ]} /> diff --git a/web/lib/api/admin.ts b/web/lib/api/admin.ts index b0a9f2b..0e6890c 100644 --- a/web/lib/api/admin.ts +++ b/web/lib/api/admin.ts @@ -363,6 +363,8 @@ export type AgentRunLog = { skillRouteTrace: string toolSearchTrace: string graphToolTrace: string + graphToolCode: string + handoffReason: string plannedToolCode: string planReason: string interruptType: string