Spaces:
Runtime error
Runtime error
File size: 3,622 Bytes
b6cd280 5710d63 b6cd280 5710d63 b6cd280 5710d63 b6cd280 5710d63 b6cd280 5710d63 b6cd280 5710d63 b6cd280 5710d63 b6cd280 | 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 | import { END, type GraphNode, START, StateGraph } from "@langchain/langgraph";
import { CoderState } from "./state.ts";
import { solidityCoderPrompt, solidityFixPrompt, solidityReviewPrompt } from "./prompts.ts";
import { compileSolidityTool } from "./tools/compile-solidity.ts";
import { createLLM } from "../../config/llm.ts";
const MAX_FIX_ATTEMPTS = 3;
/**
* Extrai apenas o bloco de código Solidity de uma resposta do LLM.
*/
function extractSolidityCode(text: string): string {
const match = text.match(/```(?:solidity)?\s*\n([\s\S]*?)```/);
if (match) return match[1].trim();
// Se não tem bloco de código, assume que a resposta inteira é código
return text.trim();
}
/**
* Nó 1: Gera o smart contract a partir dos requisitos.
*/
const generateContract: GraphNode<typeof CoderState> = async (state) => {
const llm = createLLM();
const chain = solidityCoderPrompt.pipe(llm);
const requirementsText = state.requirements
.map((r, i) => `${i + 1}. ${r}`)
.join("\n");
const result = await chain.invoke({ requirements: requirementsText });
const code = extractSolidityCode(
typeof result.content === "string" ? result.content : JSON.stringify(result.content),
);
return { contract: code, compilationErrors: [] };
};
/**
* Nó 2: Compila o contrato e armazena erros (se houver).
*/
const compileContract: GraphNode<typeof CoderState> = async (state) => {
const result = await compileSolidityTool.invoke({
sourceCode: state.contract,
filename: "Contract.sol",
});
return { compilationErrors: result.errors };
};
/**
* Nó 3: Corrige o contrato com base nos erros de compilação.
*/
const fixContract: GraphNode<typeof CoderState> = async (state) => {
const llm = createLLM();
const chain = solidityFixPrompt.pipe(llm);
const errorsText = state.compilationErrors.join("\n\n");
const result = await chain.invoke({
contract: state.contract,
errors: errorsText,
});
const code = extractSolidityCode(
typeof result.content === "string" ? result.content : JSON.stringify(result.content),
);
return { contract: code, compilationErrors: [] };
};
/**
* Nó 4: Revisa o contrato compilado quanto a segurança e boas práticas.
*/
const reviewContract: GraphNode<typeof CoderState> = async (state) => {
const llm = createLLM();
const chain = solidityReviewPrompt.pipe(llm);
const requirementsText = state.requirements.join(", ");
const result = await chain.invoke({
requirements: requirementsText,
contract: state.contract,
});
const summary =
typeof result.content === "string" ? result.content : JSON.stringify(result.content);
return { reviewSummary: summary };
};
/**
* Roteador: decide se precisa corrigir ou se pode seguir para revisão.
* Controla o número de tentativas de correção.
*/
let fixAttempts = 0;
function shouldFix(state: { compilationErrors: string[] }): "fixContract" | "reviewContract" {
if (state.compilationErrors.length > 0 && fixAttempts < MAX_FIX_ATTEMPTS) {
fixAttempts++;
return "fixContract";
}
fixAttempts = 0; // reset para próxima execução
return "reviewContract";
}
export const coderAgent = new StateGraph(CoderState)
.addNode("generateContract", generateContract)
.addNode("compileContract", compileContract)
.addNode("fixContract", fixContract)
.addNode("reviewContract", reviewContract)
.addEdge(START, "generateContract")
.addEdge("generateContract", "compileContract")
.addConditionalEdges("compileContract", shouldFix)
.addEdge("fixContract", "compileContract")
.addEdge("reviewContract", END)
.compile();
|