an3dree commited on
Commit
b5e4648
·
1 Parent(s): 834e3b9

coder agent

Browse files
patches/@langchain+core+1.1.47.patch ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ diff --git a/node_modules/@langchain/core/dist/utils/uuid/index.cjs b/node_modules/@langchain/core/dist/utils/uuid/index.cjs
2
+ index 1151178..c05caf9 100644
3
+ --- a/node_modules/@langchain/core/dist/utils/uuid/index.cjs
4
+ +++ b/node_modules/@langchain/core/dist/utils/uuid/index.cjs
5
+ @@ -36,12 +36,12 @@ Object.defineProperty(exports, "uuid_exports", {
6
+ return uuid_exports;
7
+ }
8
+ });
9
+ -exports.v1 = require_v1;
10
+ -exports.v4 = require_v4;
11
+ -exports.v5 = require_v5;
12
+ -exports.v6 = require_v6;
13
+ -exports.v7 = require_v7;
14
+ -exports.validate = require_validate;
15
+ -exports.version = require_version;
16
+ +exports.v1 = require_v1.default;
17
+ +exports.v4 = require_v4.default;
18
+ +exports.v5 = require_v5.default;
19
+ +exports.v6 = require_v6.default;
20
+ +exports.v7 = require_v7.default;
21
+ +exports.validate = require_validate.default;
22
+ +exports.version = require_version.default;
23
+
24
+ //# sourceMappingURL=index.cjs.map
25
+
src/agents/coder/agent.ts CHANGED
@@ -1,20 +1,125 @@
1
  import { END, type GraphNode, START, StateGraph } from "@langchain/langgraph";
 
2
 
3
  import { CoderState } from "./state.ts";
 
 
4
 
5
- const PLACEHOLDER_CONTRACT = `// SPDX-License-Identifier: MIT
6
- pragma solidity ^0.8.0;
7
 
8
- contract Placeholder {
9
- // TODO: implement contract based on requirements
10
- }`;
 
 
 
 
11
 
12
- const generateContract: GraphNode<typeof CoderState> = async (_state) => {
13
- return { contract: PLACEHOLDER_CONTRACT };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  };
15
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
  export const coderAgent = new StateGraph(CoderState)
17
  .addNode("generateContract", generateContract)
 
 
 
18
  .addEdge(START, "generateContract")
19
- .addEdge("generateContract", END)
 
 
 
20
  .compile();
 
1
  import { END, type GraphNode, START, StateGraph } from "@langchain/langgraph";
2
+ import { ChatGoogleGenerativeAI } from "@langchain/google-genai";
3
 
4
  import { CoderState } from "./state.ts";
5
+ import { solidityCoderPrompt, solidityFixPrompt, solidityReviewPrompt } from "./prompts.ts";
6
+ import { compileSolidityTool } from "./tools/compile-solidity.ts";
7
 
8
+ const MAX_FIX_ATTEMPTS = 3;
 
9
 
10
+ function createLLM() {
11
+ return new ChatGoogleGenerativeAI({
12
+ apiKey: process.env.GOOGLE_API_KEY || "",
13
+ model: process.env.MODEL_NAME || "gemini-2.5-flash",
14
+ temperature: 0.2,
15
+ });
16
+ }
17
 
18
+ /**
19
+ * Extrai apenas o bloco de código Solidity de uma resposta do LLM.
20
+ */
21
+ function extractSolidityCode(text: string): string {
22
+ const match = text.match(/```(?:solidity)?\s*\n([\s\S]*?)```/);
23
+ if (match) return match[1].trim();
24
+ // Se não tem bloco de código, assume que a resposta inteira é código
25
+ return text.trim();
26
+ }
27
+
28
+ /**
29
+ * Nó 1: Gera o smart contract a partir dos requisitos.
30
+ */
31
+ const generateContract: GraphNode<typeof CoderState> = async (state) => {
32
+ const llm = createLLM();
33
+ const chain = solidityCoderPrompt.pipe(llm);
34
+
35
+ const requirementsText = state.requirements
36
+ .map((r, i) => `${i + 1}. ${r}`)
37
+ .join("\n");
38
+
39
+ const result = await chain.invoke({ requirements: requirementsText });
40
+ const code = extractSolidityCode(
41
+ typeof result.content === "string" ? result.content : JSON.stringify(result.content),
42
+ );
43
+
44
+ return { contract: code, compilationErrors: [] };
45
  };
46
 
47
+ /**
48
+ * Nó 2: Compila o contrato e armazena erros (se houver).
49
+ */
50
+ const compileContract: GraphNode<typeof CoderState> = async (state) => {
51
+ const result = await compileSolidityTool.invoke({
52
+ sourceCode: state.contract,
53
+ filename: "Contract.sol",
54
+ });
55
+
56
+ return { compilationErrors: result.errors };
57
+ };
58
+
59
+ /**
60
+ * Nó 3: Corrige o contrato com base nos erros de compilação.
61
+ */
62
+ const fixContract: GraphNode<typeof CoderState> = async (state) => {
63
+ const llm = createLLM();
64
+ const chain = solidityFixPrompt.pipe(llm);
65
+
66
+ const errorsText = state.compilationErrors.join("\n\n");
67
+
68
+ const result = await chain.invoke({
69
+ contract: state.contract,
70
+ errors: errorsText,
71
+ });
72
+
73
+ const code = extractSolidityCode(
74
+ typeof result.content === "string" ? result.content : JSON.stringify(result.content),
75
+ );
76
+
77
+ return { contract: code, compilationErrors: [] };
78
+ };
79
+
80
+ /**
81
+ * Nó 4: Revisa o contrato compilado quanto a segurança e boas práticas.
82
+ */
83
+ const reviewContract: GraphNode<typeof CoderState> = async (state) => {
84
+ const llm = createLLM();
85
+ const chain = solidityReviewPrompt.pipe(llm);
86
+
87
+ const requirementsText = state.requirements.join(", ");
88
+
89
+ const result = await chain.invoke({
90
+ requirements: requirementsText,
91
+ contract: state.contract,
92
+ });
93
+
94
+ const summary =
95
+ typeof result.content === "string" ? result.content : JSON.stringify(result.content);
96
+
97
+ return { reviewSummary: summary };
98
+ };
99
+
100
+ /**
101
+ * Roteador: decide se precisa corrigir ou se pode seguir para revisão.
102
+ * Controla o número de tentativas de correção.
103
+ */
104
+ let fixAttempts = 0;
105
+
106
+ function shouldFix(state: { compilationErrors: string[] }): "fixContract" | "reviewContract" {
107
+ if (state.compilationErrors.length > 0 && fixAttempts < MAX_FIX_ATTEMPTS) {
108
+ fixAttempts++;
109
+ return "fixContract";
110
+ }
111
+ fixAttempts = 0; // reset para próxima execução
112
+ return "reviewContract";
113
+ }
114
+
115
  export const coderAgent = new StateGraph(CoderState)
116
  .addNode("generateContract", generateContract)
117
+ .addNode("compileContract", compileContract)
118
+ .addNode("fixContract", fixContract)
119
+ .addNode("reviewContract", reviewContract)
120
  .addEdge(START, "generateContract")
121
+ .addEdge("generateContract", "compileContract")
122
+ .addConditionalEdges("compileContract", shouldFix)
123
+ .addEdge("fixContract", "compileContract")
124
+ .addEdge("reviewContract", END)
125
  .compile();
src/agents/coder/outputs/.gitkeep ADDED
File without changes
src/agents/coder/prompts.ts ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { ChatPromptTemplate } from "@langchain/core/prompts";
2
+
3
+ /**
4
+ * Prompt para gerar smart contracts Solidity a partir de requisitos.
5
+ */
6
+ export const solidityCoderPrompt = ChatPromptTemplate.fromMessages([
7
+ [
8
+ "system",
9
+ `Você é um desenvolvedor sênior especialista em smart contracts Solidity.
10
+ Sua função é gerar contratos Solidity completos, compiláveis e seguros.
11
+
12
+ Regras:
13
+ - Gere código Solidity production-ready
14
+ - Use pragma solidity ^0.8.20
15
+ - NÃO use imports externos (OpenZeppelin, etc.) — implemente tudo inline
16
+ - Adicione comentários NatDoc explicativos
17
+ - Inclua eventos para todas as operações relevantes
18
+ - Use modificadores de acesso customizados (ex: onlyOwner)
19
+ - Inclua tratamento de erros com require e mensagens claras
20
+ - Siga boas práticas de segurança (checks-effects-interactions, proteção contra reentrância)
21
+ - NÃO use placeholders como "TODO" ou "implementar depois"
22
+ - O contrato deve compilar sem erros com solc 0.8.20+`,
23
+ ],
24
+ [
25
+ "human",
26
+ `Gere um smart contract Solidity completo com base nos seguintes requisitos:
27
+
28
+ {requirements}
29
+
30
+ Retorne APENAS o código Solidity completo, sem explicações adicionais.
31
+ O código deve ser auto-contido (sem imports externos).`,
32
+ ],
33
+ ]);
34
+
35
+ /**
36
+ * Prompt para corrigir erros de compilação em contratos Solidity.
37
+ */
38
+ export const solidityFixPrompt = ChatPromptTemplate.fromMessages([
39
+ [
40
+ "system",
41
+ `Você é um desenvolvedor sênior especialista em smart contracts Solidity.
42
+ Sua função é corrigir erros de compilação em contratos Solidity.
43
+
44
+ Regras:
45
+ - Corrija TODOS os erros indicados
46
+ - Mantenha a lógica de negócio original intacta
47
+ - NÃO adicione imports externos
48
+ - O contrato deve compilar sem erros com solc 0.8.20+
49
+ - Retorne APENAS o código Solidity corrigido completo`,
50
+ ],
51
+ [
52
+ "human",
53
+ `O seguinte contrato Solidity tem erros de compilação. Corrija-os:
54
+
55
+ **Código atual:**
56
+ \`\`\`solidity
57
+ {contract}
58
+ \`\`\`
59
+
60
+ **Erros de compilação:**
61
+ {errors}
62
+
63
+ Retorne APENAS o código Solidity corrigido completo, sem explicações.`,
64
+ ],
65
+ ]);
66
+
67
+ /**
68
+ * Prompt para revisar contratos Solidity quanto a segurança e boas práticas.
69
+ */
70
+ export const solidityReviewPrompt = ChatPromptTemplate.fromMessages([
71
+ [
72
+ "system",
73
+ `Você é um auditor de segurança sênior especialista em smart contracts Solidity.
74
+ Analise o contrato quanto a:
75
+ - Vulnerabilidades de segurança (reentrância, overflow, acesso não autorizado)
76
+ - Aderência a boas práticas Solidity
77
+ - Legibilidade e manutenibilidade
78
+ - Potenciais problemas de gas
79
+
80
+ Seja objetivo e conciso. Responda em português brasileiro.`,
81
+ ],
82
+ [
83
+ "human",
84
+ `Revise o seguinte smart contract:
85
+
86
+ **Requisitos originais:**
87
+ {requirements}
88
+
89
+ **Código:**
90
+ \`\`\`solidity
91
+ {contract}
92
+ \`\`\`
93
+
94
+ Forneça um resumo breve da revisão em 2-3 frases destacando se o contrato está seguro e funcional.`,
95
+ ],
96
+ ]);
src/agents/coder/run.ts ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import "dotenv/config";
2
+ import { readFileSync, mkdirSync, writeFileSync } from "node:fs";
3
+ import { resolve, dirname } from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ import { coderAgent } from "./agent.ts";
6
+
7
+ const inputPath = process.argv[2];
8
+
9
+ if (!inputPath) {
10
+ console.log("Uso: npx tsx src/agents/coder/run.ts <caminho-do-arquivo-de-requisitos>");
11
+ console.log("Exemplo: npx tsx src/agents/coder/run.ts input/requirements.md");
12
+ process.exit(1);
13
+ }
14
+
15
+ const requirementsText = readFileSync(resolve(inputPath), "utf-8");
16
+ console.log("Requisitos carregados de:", inputPath);
17
+ console.log("Gerando contrato...\n");
18
+
19
+ const result = await coderAgent.invoke({ requirements: [requirementsText] });
20
+
21
+ console.log("======= Contrato Gerado =======");
22
+ console.log(result.contract);
23
+ console.log("\n======= Erros de Compilação =======");
24
+ console.log(result.compilationErrors.length === 0 ? "Nenhum erro" : result.compilationErrors.join("\n"));
25
+ console.log("\n======= Revisão de Segurança =======");
26
+ console.log(result.reviewSummary);
27
+
28
+ const __dirname = dirname(fileURLToPath(import.meta.url));
29
+ const outputDir = resolve(__dirname, "outputs");
30
+ mkdirSync(outputDir, { recursive: true });
31
+ const outputPath = resolve(outputDir, "Contract.sol");
32
+ writeFileSync(outputPath, result.contract, "utf-8");
33
+ console.log("\nContrato salvo em:", outputPath);
src/agents/coder/state.ts CHANGED
@@ -4,4 +4,6 @@ import { z } from "zod";
4
  export const CoderState = new StateSchema({
5
  requirements: z.array(z.string()).default([]),
6
  contract: z.string().default(""),
 
 
7
  });
 
4
  export const CoderState = new StateSchema({
5
  requirements: z.array(z.string()).default([]),
6
  contract: z.string().default(""),
7
+ compilationErrors: z.array(z.string()).default([]),
8
+ reviewSummary: z.string().default(""),
9
  });
src/agents/coder/tools/compile-solidity.ts ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { tool } from "langchain";
2
+ import { z } from "zod";
3
+ import solc from "solc";
4
+
5
+ /**
6
+ * Tool que compila código Solidity usando solc e retorna erros/warnings.
7
+ */
8
+ export const compileSolidityTool = tool(
9
+ async (input) => {
10
+ const compilerInput = {
11
+ language: "Solidity",
12
+ sources: {
13
+ [input.filename]: { content: input.sourceCode },
14
+ },
15
+ settings: {
16
+ outputSelection: {
17
+ "*": { "*": ["abi", "evm.bytecode.object"] },
18
+ },
19
+ },
20
+ };
21
+
22
+ const output = JSON.parse(solc.compile(JSON.stringify(compilerInput)));
23
+
24
+ const errors = (output.errors || [])
25
+ .filter((e: { severity: string }) => e.severity === "error")
26
+ .map((e: { formattedMessage: string }) => e.formattedMessage);
27
+
28
+ const warnings = (output.errors || [])
29
+ .filter((e: { severity: string }) => e.severity === "warning")
30
+ .map((e: { formattedMessage: string }) => e.formattedMessage);
31
+
32
+ const contracts = output.contracts?.[input.filename] || {};
33
+ const contractNames = Object.keys(contracts);
34
+
35
+ return {
36
+ success: errors.length === 0,
37
+ errors,
38
+ warnings,
39
+ contracts: contractNames,
40
+ };
41
+ },
42
+ {
43
+ name: "compilar_solidity",
44
+ description: "Compila código Solidity com solc e retorna erros, warnings e contratos encontrados.",
45
+ schema: z.object({
46
+ sourceCode: z.string().describe("Código-fonte Solidity completo"),
47
+ filename: z.string().default("Contract.sol").describe("Nome do arquivo .sol"),
48
+ }),
49
+ },
50
+ );