feat(FN-1737): auto-delete child/task-worker agents and hide system agents by default

- Auto-delete spawned child agents when their parent task terminates (reportsTo cleanup)
- Auto-delete task-worker agents when their owned task completes
- Add includeSystem filter to AgentStore.list() and REST API
- Hide system agents by default on the agents page (show only user-facing agents)
- Wire includeSystem toggle through the API layer and AgentsView component
- Add changeset for @gsxdsm/fusion patch release
- Add comprehensive tests for agent cleanup and includeSystem filtering
This commit is contained in:
Fusion
2026-04-15 20:36:42 -07:00
committed by gsxdsm
parent f83d3483a6
commit c8a0876f45
13 changed files with 390 additions and 10 deletions

View File

@@ -985,12 +985,27 @@ export class AgentStore extends EventEmitter {
return agent;
}
/**
* Check if an agent is a system-generated ephemeral agent (task-worker or spawned child).
* These agents are created at runtime by the engine and should typically be hidden
* from the default agents page view.
*/
private isSystemAgent(agent: Agent): boolean {
const metadata = agent.metadata ?? {};
return (
metadata.agentKind === "task-worker" ||
metadata.type === "spawned" ||
metadata.taskWorker === true ||
metadata.managedBy === "task-executor"
);
}
/**
* List all agents, optionally filtered by state.
* @param filter - Optional filter criteria
* @returns Array of agents
*/
async listAgents(filter?: { state?: AgentState; role?: AgentCapability }): Promise<Agent[]> {
async listAgents(filter?: { state?: AgentState; role?: AgentCapability; includeSystem?: boolean }): Promise<Agent[]> {
const files = await readdir(this.agentsDir).catch(() => [] as string[]);
const agentFiles = files.filter((f) => f.endsWith(".json") && !f.includes("-heartbeats") && !f.includes("-sessions") && !f.includes("-runs") && !f.includes("-revisions"));
@@ -1004,6 +1019,9 @@ export class AgentStore extends EventEmitter {
if (filter?.state && agent.state !== filter.state) continue;
if (filter?.role && agent.role !== filter.role) continue;
// When includeSystem is explicitly false, filter out system agents
if (filter?.includeSystem === false && this.isSystemAgent(agent)) continue;
agents.push(agent);
} catch {
// Skip corrupted files