File size: 3,182 Bytes
fc99222
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2a70ee5
 
fc99222
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
import type { AgentState, StepStatus } from "../types";

export interface StepEvent {
  agent: "coder" | "auditor" | "tester";
  step: string;
  status: "running" | "done" | "error" | "skipped";
  detail?: string;
}

export const INITIAL_AGENT_STATES: AgentState[] = [
  {
    id: "coder",
    label: "CODER",
    color: "#58a6ff",
    status: "pending",
    steps: [
      { id: "coder.gen", label: "Gerando contrato", status: "pending" },
      { id: "coder.compile", label: "Compilando", status: "pending" },
      { id: "coder.review", label: "Revisando segurança", status: "pending" },
    ],
  },
  {
    id: "auditor",
    label: "AUDITOR",
    color: "#d29922",
    status: "pending",
    steps: [
      { id: "audit.scope", label: "Mapeando escopo", status: "pending" },
      { id: "audit.ctx", label: "Coletando contexto", status: "pending" },
      { id: "audit.find", label: "Analisando vulnerabilidades", status: "pending" },
      { id: "audit.judge", label: "Julgando findings", status: "pending" },
    ],
  },
  {
    id: "tester",
    label: "TESTER",
    color: "#3fb950",
    status: "pending",
    steps: [
      { id: "test.gen", label: "Codificando PoC (LLM)", status: "pending" },
      { id: "test.run", label: "Executando Sandbox (Ferramentas)", status: "pending" },
    ],
  },
];

const AGENT_ORDER = ["coder", "auditor", "tester"] as const;

const STEP_PREFIX: Record<string, string> = {
  coder: "coder.",
  auditor: "audit.",
  tester: "test.",
};

export function applyStepEvent(states: AgentState[], event: StepEvent): AgentState[] {
  const s = states.map((a) => ({ ...a, steps: a.steps.map((st) => ({ ...st })) }));

  const fullStepId = STEP_PREFIX[event.agent] + event.step;

  if (event.status === "running") {
    // Mark all preceding agents as done when a new agent starts its first step
    const agentIndex = AGENT_ORDER.indexOf(event.agent);
    for (let i = 0; i < agentIndex; i++) {
      const prev = s.find((a) => a.id === AGENT_ORDER[i]);
      if (prev && prev.status !== "done" && prev.status !== "error") {
        prev.status = "done";
        prev.steps.forEach((st) => {
          if (st.status === "pending") st.status = "done";
        });
      }
    }

    const agent = s.find((a) => a.id === event.agent);
    if (agent && agent.status === "pending") agent.status = "running";
  }

  // Update the step
  const step = s.flatMap((a) => a.steps).find((st) => st.id === fullStepId);
  if (step) {
    step.status = event.status;
    if (event.detail !== undefined) step.detail = event.detail;
  }

  // When a step finishes, check if all steps are settled → update agent status
  if (event.status !== "running") {
    const agent = s.find((a) => a.id === event.agent);
    if (agent) {
      const settled: StepStatus[] = ["done", "error", "skipped"];
      const allSettled = agent.steps.every((st) => settled.includes(st.status));
      if (allSettled) {
        const hasError = agent.steps.some((st) => st.status === "error");
        const allSkipped = agent.steps.every((st) => st.status === "skipped");
        agent.status = hasError ? "error" : allSkipped ? "skipped" : "done";
      }
    }
  }

  return s;
}