Tales-Cunha commited on
Commit
2a70ee5
·
1 Parent(s): e682a3d

update theagent to work with docker

Browse files
frontend/src/utils/status.ts CHANGED
@@ -37,10 +37,8 @@ export const INITIAL_AGENT_STATES: AgentState[] = [
37
  color: "#3fb950",
38
  status: "pending",
39
  steps: [
40
- { id: "test.oracle", label: "Preparando scaffold", status: "pending" },
41
- { id: "test.gen", label: "Gerando PoC", status: "pending" },
42
- { id: "test.run", label: "Executando Foundry", status: "pending" },
43
- { id: "test.reflect", label: "Analisando falha", status: "pending" },
44
  ],
45
  },
46
  ];
 
37
  color: "#3fb950",
38
  status: "pending",
39
  steps: [
40
+ { id: "test.gen", label: "Codificando PoC (LLM)", status: "pending" },
41
+ { id: "test.run", label: "Executando Sandbox (Ferramentas)", status: "pending" },
 
 
42
  ],
43
  },
44
  ];
src/agents/tester/graph.ts CHANGED
@@ -27,8 +27,12 @@ function routeAfterAgent(state: PoCState): "pocoToolsNode" | typeof END {
27
  return END;
28
  }
29
 
 
 
30
  // A simple node to update the toolCallCount after tools run
31
  function trackToolCallsNode(state: PoCState): Partial<PoCState> {
 
 
32
  const messages = state.messages;
33
  const lastMessage = messages[messages.length - 1];
34
 
@@ -39,6 +43,11 @@ function trackToolCallsNode(state: PoCState): Partial<PoCState> {
39
  }
40
  }
41
 
 
 
 
 
 
42
  return {
43
  toolCallCount: 1, // reducer is additive (+1)
44
  status: newStatus,
 
27
  return END;
28
  }
29
 
30
+ import { emitStep } from "../../logger.js";
31
+
32
  // A simple node to update the toolCallCount after tools run
33
  function trackToolCallsNode(state: PoCState): Partial<PoCState> {
34
+ emitStep({ agent: "tester", step: "run", status: "running" });
35
+
36
  const messages = state.messages;
37
  const lastMessage = messages[messages.length - 1];
38
 
 
43
  }
44
  }
45
 
46
+ if (newStatus === "success") {
47
+ emitStep({ agent: "tester", step: "run", status: "done" });
48
+ emitStep({ agent: "tester", step: "gen", status: "done" });
49
+ }
50
+
51
  return {
52
  toolCallCount: 1, // reducer is additive (+1)
53
  status: newStatus,
src/agents/tester/nodes/context.ts CHANGED
@@ -1,6 +1,7 @@
1
  import fs from "fs/promises";
2
  import path from "path";
3
  import { PoCState } from "../state.js";
 
4
 
5
  export async function contextNode(state: PoCState): Promise<Partial<PoCState>> {
6
  console.log("[contextNode] Preparando ambiente de testes para:", state.report.title);
 
1
  import fs from "fs/promises";
2
  import path from "path";
3
  import { PoCState } from "../state.js";
4
+ import { logger } from "../../../logger.js";
5
 
6
  export async function contextNode(state: PoCState): Promise<Partial<PoCState>> {
7
  console.log("[contextNode] Preparando ambiente de testes para:", state.report.title);
src/agents/tester/nodes/pocoAgent.ts CHANGED
@@ -2,6 +2,7 @@ import { HumanMessage, SystemMessage, AIMessage, trimMessages } from "@langchain
2
  import { PoCState } from "../state.js";
3
  import { pocoTools } from "../tools.js";
4
  import { createLLM } from "../../../config/llm.js";
 
5
 
6
  const MAX_STEPS = 30; // Max tool calls threshold
7
  const MAX_COST_USD = 3.0; // Max cost threshold
@@ -43,6 +44,7 @@ function calculateCost(inputTokens: number, outputTokens: number): number {
43
  }
44
 
45
  export async function pocoAgentNode(state: PoCState): Promise<Partial<PoCState>> {
 
46
  let messages = state.messages || [];
47
 
48
  // Check limits
@@ -126,8 +128,9 @@ export async function pocoAgentNode(state: PoCState): Promise<Partial<PoCState>>
126
  }
127
 
128
  return {
129
- messages: [...initialMessages, response],
130
  totalCost: runCost,
131
- iterations: 1, // Add 1 to total iterations tracking
 
132
  };
133
  }
 
2
  import { PoCState } from "../state.js";
3
  import { pocoTools } from "../tools.js";
4
  import { createLLM } from "../../../config/llm.js";
5
+ import { emitStep } from "../../../logger.js";
6
 
7
  const MAX_STEPS = 30; // Max tool calls threshold
8
  const MAX_COST_USD = 3.0; // Max cost threshold
 
44
  }
45
 
46
  export async function pocoAgentNode(state: PoCState): Promise<Partial<PoCState>> {
47
+ emitStep({ agent: "tester", step: "gen", status: "running" });
48
  let messages = state.messages || [];
49
 
50
  // Check limits
 
128
  }
129
 
130
  return {
131
+ messages: [response],
132
  totalCost: runCost,
133
+ toolCallCount: 1, // Reducer is additive
134
+ iterations: 1, // Reducer is additive
135
  };
136
  }
src/agents/tester/tools.ts CHANGED
@@ -186,7 +186,7 @@ export const smartContractCompileTool = tool(
186
  {
187
  cwd: sandboxDir,
188
  timeout: 30000,
189
- env: { ...process.env, PATH: `${process.env.HOME}/.foundry/bin:${process.env.PATH}` }
190
  }
191
  );
192
 
@@ -220,7 +220,7 @@ export const smartContractTestTool = tool(
220
  {
221
  cwd: sandboxDir,
222
  timeout: 60000,
223
- env: { ...process.env, PATH: `${process.env.HOME}/.foundry/bin:${process.env.PATH}` }
224
  }
225
  );
226
 
 
186
  {
187
  cwd: sandboxDir,
188
  timeout: 30000,
189
+ env: { ...process.env }
190
  }
191
  );
192
 
 
220
  {
221
  cwd: sandboxDir,
222
  timeout: 60000,
223
+ env: { ...process.env }
224
  }
225
  );
226
 
src/benchmark/runSyntheticEvaluation.ts CHANGED
@@ -38,9 +38,9 @@ function appendCsvRow(row: string[]) {
38
  async function runEvaluation() {
39
  const cases = await parseJSONL(JSONL_FILE);
40
 
41
- // Only evaluate 10 hard cases to match the amount of easy/intermediate cases
42
- const targetCases = cases.filter(c => c.complexity === "hard").slice(0, 10);
43
- console.log(`Iniciando avaliação para ${targetCases.length} projetos sintéticos difíceis...`);
44
 
45
  const csvHeaders = [
46
  "Task_ID",
 
38
  async function runEvaluation() {
39
  const cases = await parseJSONL(JSONL_FILE);
40
 
41
+ // Roda a avaliação para os datasets easy e intermediate a pedido do usuário
42
+ const targetCases = cases.filter(c => c.complexity === "easy" || c.complexity === "intermediate");
43
+ console.log(`Iniciando avaliação para ${targetCases.length} projetos sintéticos (easy/intermediate)...`);
44
 
45
  const csvHeaders = [
46
  "Task_ID",
src/server.ts CHANGED
@@ -1,6 +1,6 @@
1
  import "dotenv/config";
2
 
3
- import { mkdirSync, writeFileSync } from "node:fs";
4
  import { resolve } from "node:path";
5
  import { tmpdir } from "node:os";
6
  import { serve } from "@hono/node-server";
@@ -13,6 +13,7 @@ import { coderAgent } from "./agents/coder/agent.ts";
13
  import { auditorAgent } from "./agents/auditor/agent.ts";
14
  import { testerAgent } from "./agents/tester/agent.ts";
15
  import { mapFindingToReport } from "./utils/mapFinding.js";
 
16
  import { logger, setLogSink, clearLogSink, setStepSink, clearStepSink } from "./logger.ts";
17
 
18
  const app = new Hono();
@@ -87,18 +88,41 @@ app.post("/api/run", (c) => {
87
  coderResult.contract,
88
  auditorResult.repoContext // ← now forwarded to tester
89
  );
90
- report.customSandboxDir = outputDir; // tester runs in real project sandbox
91
- const testerResult = await testerAgent.invoke({ report });
 
 
 
 
 
 
 
92
 
93
  logger.info(`[Tester] Execução concluída com status: ${testerResult.status}`);
94
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
95
  // Garante que o objeto enviado tem exatamente o que o front espera
96
  await send(
97
  "tester",
98
  JSON.stringify({
99
  status: testerResult.status,
100
- pocCode: testerResult.pocCode,
101
- executionLogs: testerResult.executionLogs,
102
  iterations: testerResult.iterations,
103
  }),
104
  );
 
1
  import "dotenv/config";
2
 
3
+ import { mkdirSync, writeFileSync, readFileSync } from "node:fs";
4
  import { resolve } from "node:path";
5
  import { tmpdir } from "node:os";
6
  import { serve } from "@hono/node-server";
 
13
  import { auditorAgent } from "./agents/auditor/agent.ts";
14
  import { testerAgent } from "./agents/tester/agent.ts";
15
  import { mapFindingToReport } from "./utils/mapFinding.js";
16
+ import { createEmptyFoundryProject } from "./utils/forgeSandbox.js";
17
  import { logger, setLogSink, clearLogSink, setStepSink, clearStepSink } from "./logger.ts";
18
 
19
  const app = new Hono();
 
88
  coderResult.contract,
89
  auditorResult.repoContext // ← now forwarded to tester
90
  );
91
+ const sandboxDir = resolve(tmpdir(), `talp1-tester-${Date.now()}`);
92
+ await createEmptyFoundryProject(sandboxDir, coderResult.contract, "Contract");
93
+ report.customSandboxDir = sandboxDir; // ← tester runs in real project sandbox
94
+ report.affectedContract.sourceFilePath = "src/Contract.sol"; // Fix bug with relative path
95
+
96
+ const testerResult = await testerAgent.invoke(
97
+ { report },
98
+ { recursionLimit: 100, configurable: { sandboxDir } }
99
+ );
100
 
101
  logger.info(`[Tester] Execução concluída com status: ${testerResult.status}`);
102
 
103
+ let finalPocCode = testerResult.pocCode || "";
104
+ try {
105
+ finalPocCode = readFileSync(resolve(sandboxDir, "test/Exploit.t.sol"), "utf-8");
106
+ } catch (e) {
107
+ // Ignorar se não criou
108
+ }
109
+
110
+ let finalExecutionLogs: string[] = testerResult.executionLogs || [];
111
+ if (finalExecutionLogs.length === 0 && testerResult.messages) {
112
+ const testMsgs = testerResult.messages.filter((m: any) => m._getType() === "tool" && m.name === "smart_contract_test");
113
+ if (testMsgs.length > 0) {
114
+ const content = testMsgs[testMsgs.length - 1].content;
115
+ finalExecutionLogs = [typeof content === "string" ? content : JSON.stringify(content)];
116
+ }
117
+ }
118
+
119
  // Garante que o objeto enviado tem exatamente o que o front espera
120
  await send(
121
  "tester",
122
  JSON.stringify({
123
  status: testerResult.status,
124
+ pocCode: finalPocCode,
125
+ executionLogs: finalExecutionLogs,
126
  iterations: testerResult.iterations,
127
  }),
128
  );
src/utils/forgeSandbox.ts CHANGED
@@ -6,7 +6,7 @@ export async function createEmptyFoundryProject(targetDir: string, sourceCode: s
6
  await fs.mkdir(targetDir, { recursive: true });
7
  execSync("forge init --no-git --force", {
8
  cwd: targetDir,
9
- env: { ...process.env, PATH: `${process.env.PATH}:/home/tales/.foundry/bin` }
10
  });
11
 
12
  // Clean up default files
 
6
  await fs.mkdir(targetDir, { recursive: true });
7
  execSync("forge init --no-git --force", {
8
  cwd: targetDir,
9
+ env: { ...process.env } // Deixa o PATH nativo agir (configurado pelo bash ou Dockerfile)
10
  });
11
 
12
  // Clean up default files