Spaces:
Runtime error
Runtime error
File size: 6,288 Bytes
2f30981 | 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 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 | import "dotenv/config";
import { readFileSync, writeFileSync, existsSync } from "node:fs";
import { resolve } from "node:path";
import { coderAgent } from "../src/agents/coder/agent.ts";
// βββ Config ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
const FORMAL_EVAL_PATH =
process.env.FORMAL_EVAL_PATH ??
resolve("..", "formal-eval", "data", "FormalEval.jsonl");
const OUTPUT_PATH = process.env.BENCHMARK_OUTPUT ?? resolve("benchmarks", "samples.jsonl");
const SAMPLES_PER_TASK = Number(process.env.SAMPLES_PER_TASK ?? "1");
const SKIP_REVIEW = process.env.SKIP_REVIEW !== "false"; // skip review by default for speed
// βββ Types βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
interface FormalEvalProblem {
task_id: string;
complexity: string;
description: string;
prompt: string;
canonical_solution: string;
test: string;
entry_point: string;
}
interface SampleOutput {
task_id: string;
completion: string;
}
// βββ Helpers βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
function readProblems(path: string): FormalEvalProblem[] {
const content = readFileSync(path, "utf-8");
return content
.split("\n")
.filter((line) => line.trim())
.map((line) => JSON.parse(line));
}
/**
* Extrai a "completion" (body do contrato) a partir do contrato completo gerado.
* O FormalEval espera: prompt + completion = contrato completo.
* EntΓ£o precisamos remover tudo que jΓ‘ estΓ‘ no prompt.
*/
function extractCompletion(generatedContract: string, prompt: string): string {
// EstratΓ©gia 1: Se o contrato gerado contΓ©m o prompt exato, pegar o que vem depois
const promptTrimmed = prompt.trimEnd();
const idx = generatedContract.indexOf(promptTrimmed);
if (idx !== -1) {
return generatedContract.slice(idx + promptTrimmed.length);
}
// EstratΓ©gia 2: Encontrar a declaraΓ§Γ£o "contract <Name> {" e pegar o body
// O prompt sempre termina com "contract <Name> {\n"
const contractDeclMatch = prompt.match(/contract\s+(\w+)\s*\{?\s*$/m);
if (contractDeclMatch) {
const contractName = contractDeclMatch[1];
const pattern = new RegExp(`contract\\s+${contractName}\\s*\\{`);
const match = generatedContract.match(pattern);
if (match?.index !== undefined) {
const afterDecl = generatedContract.slice(match.index + match[0].length);
return afterDecl;
}
}
// EstratΓ©gia 3: Fallback β Tenta remover pragma + imports + declaraΓ§Γ£o atΓ© "{"
const lines = generatedContract.split("\n");
let bodyStart = 0;
for (let i = 0; i < lines.length; i++) {
if (lines[i].match(/contract\s+\w+.*\{/)) {
bodyStart = i + 1;
break;
}
}
return lines.slice(bodyStart).join("\n");
}
/**
* Adapta o prompt do FormalEval para ser interpretado pelo Coder Agent.
* Inclui instruΓ§Γ£o explΓcita para gerar apenas o body.
*/
function buildRequirements(problem: FormalEvalProblem): string {
return `Complete the following Solidity contract. Generate ONLY the contract body (state variables, functions, and closing brace "}").
Do NOT include the SPDX license, pragma, or contract declaration β they are already provided.
The code must compile with solc ^0.8.19.
Here is the contract declaration with its specification:
${problem.prompt}
IMPORTANT: Return ONLY the code that goes INSIDE the contract (after the opening brace). Include the closing "}" at the end.`;
}
// βββ Main ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
async function main() {
if (!existsSync(FORMAL_EVAL_PATH)) {
console.error(`FormalEval dataset not found at: ${FORMAL_EVAL_PATH}`);
console.error("Set FORMAL_EVAL_PATH env variable to the correct path.");
process.exit(1);
}
const problems = readProblems(FORMAL_EVAL_PATH);
console.log(`Loaded ${problems.length} problems from FormalEval`);
console.log(`Generating ${SAMPLES_PER_TASK} sample(s) per task...`);
console.log(`Output: ${OUTPUT_PATH}\n`);
const samples: SampleOutput[] = [];
let completed = 0;
for (const problem of problems) {
for (let s = 0; s < SAMPLES_PER_TASK; s++) {
const label = `[${problem.task_id}] (${problem.complexity}) sample ${s + 1}/${SAMPLES_PER_TASK}`;
console.log(`β ${label}: ${problem.description}`);
try {
const requirements = buildRequirements(problem);
const result = await coderAgent.invoke({ requirements: [requirements] });
const generated = result.contract;
const completion = extractCompletion(generated, problem.prompt);
samples.push({ task_id: problem.task_id, completion });
const hasErrors = result.compilationErrors.length > 0;
console.log(` β Done${hasErrors ? ` (with ${result.compilationErrors.length} compile errors)` : ""}`);
} catch (error) {
const msg = error instanceof Error ? error.message : String(error);
console.error(` β Failed: ${msg}`);
// Still emit an empty completion so FormalEval doesn't complain about missing tasks
samples.push({ task_id: problem.task_id, completion: "// generation failed\n}\n" });
}
completed++;
}
}
// Write JSONL output
const jsonl = samples.map((s) => JSON.stringify(s)).join("\n") + "\n";
writeFileSync(OUTPUT_PATH, jsonl, "utf-8");
console.log(`\n${"β".repeat(60)}`);
console.log(`Benchmark complete: ${completed} completions generated`);
console.log(`Output saved to: ${OUTPUT_PATH}`);
console.log(`\nTo evaluate, run:`);
console.log(` cd ../formal-eval && evaluate_formal_correctness ${resolve(OUTPUT_PATH)}`);
}
main().catch((err) => {
console.error("Fatal error:", err);
process.exit(1);
});
|