Spaces:
Runtime error
Runtime error
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.
|
| 41 |
-
{ id: "test.
|
| 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: [
|
| 130 |
totalCost: runCost,
|
| 131 |
-
|
|
|
|
| 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
|
| 190 |
}
|
| 191 |
);
|
| 192 |
|
|
@@ -220,7 +220,7 @@ export const smartContractTestTool = tool(
|
|
| 220 |
{
|
| 221 |
cwd: sandboxDir,
|
| 222 |
timeout: 60000,
|
| 223 |
-
env: { ...process.env
|
| 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 |
-
//
|
| 42 |
-
const targetCases = cases.filter(c => c.complexity === "
|
| 43 |
-
console.log(`Iniciando avaliação para ${targetCases.length} projetos sintéticos
|
| 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 |
-
|
| 91 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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:
|
| 101 |
-
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
|
| 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
|