feat(canvas): 云端 Agent - 完成策略分层、节点能力注册与可解释审批改造
This commit is contained in:
@@ -141,6 +141,114 @@ func TestCloudAgentLegacyRunSurvivesTaskInputCompaction(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestCloudAgentTerminalRunWithOlderCapabilityCanContinueOnCurrentContract(t *testing.T) {
|
||||
s, db, _, _ := creationTestService(t)
|
||||
if err := db.Create(&model.CanvasProject{ID: "agent-canvas", UserID: "user", PayloadJSON: `{"nodes":[]}`}).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
parentRequest := agentTestRequest()
|
||||
parentRequest.IdempotencyKey = "older-capability-parent"
|
||||
parent, err := s.CreateCloudAgentRun("user", parentRequest, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
parentExecution, err := s.repo.CloudAgent("user", parent.ID)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
parentState, err := cloudAgentDecode(parentExecution)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
parentState.Policy.CapabilitySetVersion = "canvas-capabilities/v1"
|
||||
parentState.Policy.CapabilitySetHash = agentProfileHash("historical capability contract")
|
||||
if err = cloudAgentSave(parentExecution, &parentState); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err = db.Model(&model.CloudAgentExecution{}).Where("id = ?", parent.ID).Updates(map[string]any{
|
||||
"status": "completed", "state_json": parentExecution.StateJSON,
|
||||
}).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err = db.Model(&model.Task{}).Where("id = ?", parent.ID).Updates(map[string]any{
|
||||
"status": model.TaskStatusSucceeded, "result_json": `{"text":"旧合同下的可信回复"}`,
|
||||
}).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
historicalStateJSON := parentExecution.StateJSON
|
||||
|
||||
childRequest := agentTestRequest()
|
||||
childRequest.Prompt = "继续操作"
|
||||
childRequest.IdempotencyKey = "current-capability-child"
|
||||
child, err := s.CreateCloudAgentRun("user", childRequest, parent.ID)
|
||||
if err != nil {
|
||||
t.Fatalf("terminal historical run cannot continue: %v", err)
|
||||
}
|
||||
childExecution, err := s.repo.CloudAgent("user", child.ID)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
childState, err := cloudAgentDecode(childExecution)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err = validateCloudAgentPolicySnapshot(childState.Policy); err != nil {
|
||||
t.Fatalf("child did not use the current execution contract: %v", err)
|
||||
}
|
||||
if childState.Policy.CapabilitySetVersion != cloudAgentCapabilitySetVersion || childState.Policy.CapabilitySetHash != cloudAgentCapabilitySetHash() {
|
||||
t.Fatalf("child capability contract is stale: %+v", childState.Policy)
|
||||
}
|
||||
if childState.ParentID != parent.ID || len(childState.TextHistory) != 2 || childState.TextHistory[1].Content != "旧合同下的可信回复" {
|
||||
t.Fatalf("historical conversation context was not preserved: %+v", childState)
|
||||
}
|
||||
var storedParent model.CloudAgentExecution
|
||||
if err = db.First(&storedParent, "id = ?", parent.ID).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if storedParent.StateJSON != historicalStateJSON {
|
||||
t.Fatal("continuation mutated the frozen parent runtime")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCloudAgentActiveRunWithOlderCapabilityIsTerminatedWithoutResume(t *testing.T) {
|
||||
s, db, _, _ := creationTestService(t)
|
||||
if err := db.Create(&model.CanvasProject{ID: "agent-canvas", UserID: "user", PayloadJSON: `{"nodes":[]}`}).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
req := agentTestRequest()
|
||||
req.IdempotencyKey = "older-active-contract"
|
||||
run, err := s.CreateCloudAgentRun("user", req, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
execution, err := s.repo.CloudAgent("user", run.ID)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
state, err := cloudAgentDecode(execution)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
state.Policy.CapabilitySetVersion = "canvas-capabilities/v1"
|
||||
state.Policy.CapabilitySetHash = agentProfileHash("historical capability contract")
|
||||
if err = cloudAgentSave(execution, &state); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err = db.Model(&model.CloudAgentExecution{}).Where("id = ?", run.ID).Update("state_json", execution.StateJSON).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err = s.advanceCloudAgentByID("user", run.ID); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
execution, err = s.repo.CloudAgent("user", run.ID)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if execution.Status != "failed" || !strings.Contains(execution.FailureMessage, "旧版执行合同") {
|
||||
t.Fatalf("stale active contract was resumed or failed opaquely: status=%s message=%q", execution.Status, execution.FailureMessage)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCloudAgentValidation(t *testing.T) {
|
||||
for _, mutate := range []func(*CloudAgentRequest){
|
||||
func(r *CloudAgentRequest) { r.PermissionMode = "unrestricted" },
|
||||
@@ -346,7 +454,7 @@ func TestCloudAgentToolLoopPersistsApprovalAndAppliesCanvasWrite(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
req := agentTestRequest()
|
||||
req.Thinking = true
|
||||
req.ReasoningMode = "deep"
|
||||
req.PermissionMode = "request_approval"
|
||||
root, err := s.CreateCloudAgentRun("user", req, "")
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user