diff --git a/internal/builders/agent_run_log_builder.go b/internal/builders/agent_run_log_builder.go
index 45fda25..8eeed79 100644
--- a/internal/builders/agent_run_log_builder.go
+++ b/internal/builders/agent_run_log_builder.go
@@ -3,12 +3,14 @@ package builders
import (
"cs-agent/internal/models"
"cs-agent/internal/pkg/dto/response"
+ "strings"
)
func BuildAgentRunLog(item *models.AgentRunLog) response.AgentRunLogResponse {
if item == nil {
return response.AgentRunLogResponse{}
}
+ hitlStatus, hitlStatusName, hitlSummary := resolveAgentRunLogHITL(item)
return response.AgentRunLogResponse{
ID: item.ID,
ConversationID: item.ConversationID,
@@ -28,6 +30,9 @@ func BuildAgentRunLog(item *models.AgentRunLog) response.AgentRunLogResponse {
PlanReason: item.PlanReason,
InterruptType: item.InterruptType,
ResumeSource: item.ResumeSource,
+ HitlStatus: hitlStatus,
+ HitlStatusName: hitlStatusName,
+ HitlSummary: hitlSummary,
FinalAction: item.FinalAction,
FinalStatus: item.FinalStatus,
ReplyText: item.ReplyText,
@@ -37,3 +42,24 @@ func BuildAgentRunLog(item *models.AgentRunLog) response.AgentRunLogResponse {
CreatedAt: item.CreatedAt.Format("2006-01-02 15:04:05"),
}
}
+
+func resolveAgentRunLogHITL(item *models.AgentRunLog) (status, statusName, summary string) {
+ if item == nil {
+ return "", "", ""
+ }
+ replyText := strings.TrimSpace(item.ReplyText)
+ switch {
+ case strings.TrimSpace(item.FinalStatus) == "interrupted":
+ return "pending", "等待确认", "Graph Tool 已发起确认,正在等待用户回复。"
+ case strings.TrimSpace(item.FinalStatus) == "expired":
+ return "expired", "已过期", "确认 checkpoint 已失效,需要重新发起。"
+ case strings.Contains(replyText, "已取消本次工单创建") || strings.Contains(replyText, "已取消本次转人工"):
+ return "cancelled", "已取消", "用户已明确取消,本次确认流程已终止。"
+ case strings.TrimSpace(item.ResumeSource) != "":
+ return "confirmed", "已确认", "用户确认后已恢复执行,并完成后续流程。"
+ case strings.TrimSpace(item.InterruptType) != "":
+ return "triggered", "已触发", "本次运行涉及确认式 HITL 流程。"
+ default:
+ return "", "", ""
+ }
+}
diff --git a/internal/pkg/dto/response/skill_response.go b/internal/pkg/dto/response/skill_response.go
index a710b98..52d93b4 100644
--- a/internal/pkg/dto/response/skill_response.go
+++ b/internal/pkg/dto/response/skill_response.go
@@ -56,6 +56,9 @@ type AgentRunLogResponse struct {
PlanReason string `json:"planReason"`
InterruptType string `json:"interruptType"`
ResumeSource string `json:"resumeSource"`
+ HitlStatus string `json:"hitlStatus"`
+ HitlStatusName string `json:"hitlStatusName"`
+ HitlSummary string `json:"hitlSummary"`
FinalAction string `json:"finalAction"`
FinalStatus string `json:"finalStatus"`
ReplyText string `json:"replyText"`
diff --git a/web/app/(console)/agent-run-logs/page.tsx b/web/app/(console)/agent-run-logs/page.tsx
index 7ab8450..cdf6d7c 100644
--- a/web/app/(console)/agent-run-logs/page.tsx
+++ b/web/app/(console)/agent-run-logs/page.tsx
@@ -79,6 +79,21 @@ function actionBadgeVariant(action: string) {
}
}
+function hitlBadgeVariant(status: string) {
+ switch (status) {
+ case "pending":
+ return "secondary" as const
+ case "confirmed":
+ return "default" as const
+ case "cancelled":
+ return "outline" as const
+ case "expired":
+ return "destructive" as const
+ default:
+ return "secondary" as const
+ }
+}
+
export default function DashboardAgentRunLogsPage() {
const [keywordInput, setKeywordInput] = useState("")
const [plannedActionInput, setPlannedActionInput] = useState("all")
@@ -323,6 +338,13 @@ export default function DashboardAgentRunLogsPage() {