multi-agent-smart-contracts / src /benchmark /runSyntheticEvaluation.ts
Tales-Cunha
update theagent to work with docker
2a70ee5
Raw
History Blame Contribute Delete
4.9 kB
import "dotenv/config";
import fs from "fs/promises";
import path from "path";
import { execSync } from "child_process";
import { testerAgent } from "../agents/tester/agent.js";
import { VulnerabilityReport } from "../agents/tester/types.js";
const JSONL_FILE = path.join(process.cwd(), "data", "benchmark_synthetic.jsonl");
const TEMP_DIR = path.join(process.cwd(), "temp_eval_run");
const CSV_FILE = path.join(process.cwd(), "data", "synthetic_evaluation_results.csv");
async function parseJSONL(filepath: string) {
const content = await fs.readFile(filepath, "utf8");
return content.split("\n").filter(l => l.trim().length > 0).map(l => JSON.parse(l));
}
async function createEmptyFoundryProject(targetDir: string, sourceCode: string, contractName: string) {
await fs.mkdir(targetDir, { recursive: true });
execSync("forge init --no-git --force", {
cwd: targetDir,
env: { ...process.env, PATH: `${process.env.PATH}:/home/tales/.foundry/bin` }
});
// Clean up default files
await fs.rm(path.join(targetDir, "src", "Counter.sol"), { force: true });
await fs.rm(path.join(targetDir, "test", "Counter.t.sol"), { force: true });
await fs.rm(path.join(targetDir, "script", "Counter.s.sol"), { force: true });
// Write vulnerable contract
await fs.writeFile(path.join(targetDir, "src", `${contractName}.sol`), sourceCode);
}
function appendCsvRow(row: string[]) {
const line = row.map(cell => `"${String(cell).replace(/"/g, '""')}"`).join(";") + "\n";
import("fs").then(m => m.appendFileSync(CSV_FILE, line));
}
async function runEvaluation() {
const cases = await parseJSONL(JSONL_FILE);
// Roda a avaliação para os datasets easy e intermediate a pedido do usuário
const targetCases = cases.filter(c => c.complexity === "easy" || c.complexity === "intermediate");
console.log(`Iniciando avaliação para ${targetCases.length} projetos sintéticos (easy/intermediate)...`);
const csvHeaders = [
"Task_ID",
"Complexity",
"Time_Sec",
"Pass_at_1",
"Tool_Calls",
"Total_Cost_USD",
"Final_Status",
"Error_Msg"
];
await fs.mkdir(path.join(process.cwd(), "data"), { recursive: true });
await fs.writeFile(CSV_FILE, csvHeaders.join(";") + "\n");
let totalCost = 0;
let passed = 0;
for (const c of targetCases) {
console.log(`\n\n${"=".repeat(60)}`);
console.log(`=== INICIANDO CASO: ${c.task_id} ===`);
console.log(`${"=".repeat(60)}`);
const startTime = Date.now();
const sandboxDir = path.join(TEMP_DIR, c.repo_name);
// Setup Forge
const contractName = c.repo_name.replace(/-/g, ""); // Simplified contract name parsing
await createEmptyFoundryProject(sandboxDir, c.source_code, contractName);
const report: VulnerabilityReport = {
id: c.task_id,
severity: c.impact || "high",
type: c.expected_vulnerability,
title: c.task_id,
description: c.annotation,
affectedContract: { name: contractName, sourceCode: c.source_code, sourceFilePath: `src/${contractName}.sol` },
attackVector: c.expected_vulnerability,
customSandboxDir: sandboxDir
};
console.log(`[CENÁRIO SINTÉTICO] Gerando exploit para ${c.task_id}...`);
const result = await testerAgent.invoke(
{ report },
{
recursionLimit: 100,
configurable: { sandboxDir }
}
) as any;
const timeSec = ((Date.now() - startTime) / 1000).toFixed(1);
const passAt1 = result.status === "success";
const toolCalls = result.toolCallCount || 0;
const cost = result.totalCost || 0;
totalCost += cost;
if (passAt1) passed++;
console.log(`=> Status: ${result.status} | Tools: ${toolCalls} | Cost: $${cost.toFixed(2)} | Time: ${timeSec}s`);
if (!passAt1) {
console.log("--- LLM HISTORY ---");
for (const m of result.messages) {
console.log(`[${m._getType()}] ${m.content.substring(0, 200)}...`);
if (m._getType() === "ai" && m.tool_calls) {
console.log("Tool calls:", JSON.stringify(m.tool_calls));
}
if (m._getType() === "tool" && m.name === "smart_contract_test") {
console.log("Test Output:", m.content);
}
}
console.log("-------------------");
}
appendCsvRow([
c.task_id,
c.complexity,
timeSec,
passAt1 ? "TRUE" : "FALSE",
toolCalls.toString(),
cost.toFixed(4),
result.status,
result.lastError || ""
]);
}
console.log(`\n\nAVALIAÇÃO CONCLUÍDA!`);
console.log(`Accuracy (Pass@1): ${((passed / targetCases.length) * 100).toFixed(1)}% (${passed}/${targetCases.length})`);
console.log(`Total Cost: $${totalCost.toFixed(2)}`);
console.log(`Resultados em: ${CSV_FILE}`);
}
runEvaluation().catch(err => {
console.error("Fatal error during evaluation:", err);
process.exit(1);
});