Files
goclaw/internal/tools/subagent_roster_test.go
Duc Nguyenandntduc bb7712a9ff fix(collaboration): harden delegated task isolation (#1486)
* feat(collaboration): isolate delegated artifacts and child runs

Isolate delegated inputs and outputs behind secure artifact exchange lifecycles. Scope Agent Link tasks by tenant and root agent, and enforce delegation spawn-tree boundaries. Add process-wide child-run admission and preserve logical media paths across native, MCP, and sandbox execution.

* fix(collaboration): harden delegated task isolation

Enforce tenant and root-agent task scope across migrations and stores. Add exactly-once async completion delivery, delegated sandbox boundaries, and confined artifact and media recovery across runtime surfaces.

* fix(collaboration): recover interrupted async tasks

* fix(collaboration): normalize persisted child-run status

---------

Co-authored-by: ntduc <ntduc@cpp.ai.vn>
2026-07-30 14:17:40 +07:00

65 lines
1.9 KiB
Go

package tools
import (
"strings"
"testing"
"github.com/google/uuid"
)
func TestRosterForParentSeparatesActiveFromRetainedTasks(t *testing.T) {
tenantID := uuid.New()
rootID := uuid.New()
manager := NewSubagentManager(nil, nil, "", nil, nil, SubagentConfig{
MaxChildrenPerAgent: 5,
})
manager.tasks = map[string]*SubagentTask{
"completed": {
ID: "completed",
ParentID: "parent",
RootAgentID: rootID,
RootAgentKey: "parent",
OriginTenantID: tenantID,
Label: "completed task",
Status: TaskStatusCompleted,
CreatedAt: 1,
spawnConfig: SubagentConfig{MaxChildrenPerAgent: 3},
},
"running": {
ID: "running",
ParentID: "parent",
RootAgentID: rootID,
RootAgentKey: "parent",
OriginTenantID: tenantID,
Label: "running task",
Status: TaskStatusRunning,
CreatedAt: 2,
spawnConfig: SubagentConfig{MaxChildrenPerAgent: 7},
},
"failed": {
ID: "failed",
ParentID: "parent",
RootAgentID: rootID,
RootAgentKey: "parent",
OriginTenantID: tenantID,
Label: "failed task",
Status: TaskStatusFailed,
CreatedAt: 3,
spawnConfig: SubagentConfig{MaxChildrenPerAgent: 9},
},
}
roster := manager.RosterForParent(TaskScope{TenantID: tenantID, RootAgentID: rootID, RootAgentKey: "parent"})
if roster.Active != 1 || roster.Total != 3 || roster.MaxPerAgent != 9 {
t.Fatalf("roster counts = %#v, want 1 active / 3 retained / max 9", roster)
}
instruction := BuildReplyInstruction(roster)
if !strings.Contains(instruction, "1 active / 9 max; 3 retained total") {
t.Fatalf("instruction missing active/retained counts:\n%s", instruction)
}
if !strings.Contains(instruction, "1 subagent(s) still running") {
t.Fatalf("instruction missing running state:\n%s", instruction)
}
}