feat: add workflow run audit graph component and enhance workflow run details

This commit is contained in:
mlogclub
2026-06-25 21:42:14 +08:00
parent b806a2208b
commit d11080e14b
9 changed files with 501 additions and 1 deletions
+3
View File
@@ -134,6 +134,9 @@ func BuildAIWorkflowRunDetail(item *models.AIWorkflowRun, nodes []models.AIWorkf
func BuildAIWorkflowRunDetailWithContext(item *models.AIWorkflowRun, nodes []models.AIWorkflowNodeRun, workflow *models.AIWorkflow, version *models.AIWorkflowVersion, agent *models.AIAgent) response.AIWorkflowRunResponse {
ret := BuildAIWorkflowRunWithContext(item, workflow, version, agent)
if version != nil {
ret.Definition = parseWorkflowDefinition(version.Definition)
}
ret.Nodes = BuildAIWorkflowNodeRunList(nodes)
return ret
}
@@ -1,9 +1,11 @@
package builders
import (
"encoding/json"
"testing"
"time"
"agent-desk/internal/ai/workflow/dsl"
workflowregistry "agent-desk/internal/ai/workflow/registry"
"agent-desk/internal/models"
)
@@ -65,6 +67,40 @@ func TestBuildAIWorkflowRunIncludesAuditDisplayFields(t *testing.T) {
}
}
func TestBuildAIWorkflowRunDetailIncludesPublishedDefinitionSnapshot(t *testing.T) {
definition := dsl.Definition{
SchemaVersion: 1,
EntryNodeID: "start_1",
Nodes: []dsl.Node{
{ID: "start_1", Type: workflowregistry.NodeTypeStart, Name: "开始"},
{ID: "reply_1", Type: workflowregistry.NodeTypeLLMReply, Name: "运行时回复"},
},
Edges: []dsl.Edge{{ID: "edge_start_reply", Source: "start_1", Target: "reply_1"}},
}
buf, err := json.Marshal(definition)
if err != nil {
t.Fatalf("marshal definition: %v", err)
}
resp := BuildAIWorkflowRunDetailWithContext(
&models.AIWorkflowRun{ID: 9, WorkflowVersionID: 22, Status: 1, StartedAt: time.Now()},
nil,
&models.AIWorkflow{Name: "当前 Workflow 草稿不应参与审计图"},
&models.AIWorkflowVersion{Version: 3, Definition: string(buf)},
&models.AIAgent{Name: "售后 Agent"},
)
if resp.Definition.EntryNodeID != "start_1" {
t.Fatalf("expected run detail definition from published version, got %#v", resp.Definition)
}
if len(resp.Definition.Nodes) != 2 || resp.Definition.Nodes[1].Name != "运行时回复" {
t.Fatalf("expected published definition nodes, got %#v", resp.Definition.Nodes)
}
if len(resp.Definition.Edges) != 1 || resp.Definition.Edges[0].ID != "edge_start_reply" {
t.Fatalf("expected published definition edges, got %#v", resp.Definition.Edges)
}
}
func hasResponseVariable(items []workflowregistry.VariableSpec, name string) bool {
for _, item := range items {
if item.Name == name {
@@ -74,6 +74,7 @@ type AIWorkflowRunResponse struct {
ErrorMessage string `json:"errorMessage"`
CreatedAt string `json:"createdAt"`
UpdatedAt string `json:"updatedAt"`
Definition dsl.Definition `json:"definition"`
Nodes []AIWorkflowNodeRunResponse `json:"nodes,omitempty"`
}
+12 -1
View File
@@ -163,7 +163,18 @@ func TestAIWorkflowServiceRunListAndDetail(t *testing.T) {
if err := sqls.DB().Create(&workflow).Error; err != nil {
t.Fatalf("create workflow: %v", err)
}
version := models.AIWorkflowVersion{WorkflowID: workflow.ID, Version: 7, Status: enums.StatusOk}
versionDefinition := validAIWorkflowDefinition()
versionDefinition.Nodes[1].Name = "运行时回复"
versionDefinitionJSON, err := json.Marshal(versionDefinition)
if err != nil {
t.Fatalf("marshal version definition: %v", err)
}
version := models.AIWorkflowVersion{
WorkflowID: workflow.ID,
Version: 7,
Status: enums.StatusOk,
Definition: string(versionDefinitionJSON),
}
if err := sqls.DB().Create(&version).Error; err != nil {
t.Fatalf("create workflow version: %v", err)
}