Uanderson Silva commited on
Commit
b6cd280
·
1 Parent(s): 38fb424

implement base agents

Browse files
package.json CHANGED
@@ -3,6 +3,7 @@
3
  "version": "0.0.1",
4
  "description": "Projeto de TALP 1",
5
  "main": "dist/index.js",
 
6
  "scripts": {
7
  "test": "vitest",
8
  "coverage": "vitest run --coverage",
 
3
  "version": "0.0.1",
4
  "description": "Projeto de TALP 1",
5
  "main": "dist/index.js",
6
+ "type": "module",
7
  "scripts": {
8
  "test": "vitest",
9
  "coverage": "vitest run --coverage",
src/agents/auditor/agent.ts ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { END, type GraphNode, START, StateGraph } from "@langchain/langgraph";
2
+
3
+ import { AuditorState } from "./state.ts";
4
+ import { slitherTool } from "./tools/slither-tool.ts";
5
+
6
+ const PLACEHOLDER_VULNERABILITIES = [
7
+ { type: "reentrancy", severity: "high", description: "Unchecked external call allows reentrancy attack." },
8
+ { type: "integer-overflow", severity: "medium", description: "Arithmetic operation may overflow." },
9
+ ];
10
+
11
+ const auditContract: GraphNode<typeof AuditorState> = async (state) => {
12
+ await slitherTool.invoke({ solidityFile: state.solidityFile });
13
+ return { vulnerabilities: PLACEHOLDER_VULNERABILITIES };
14
+ };
15
+
16
+ export const auditorAgent = new StateGraph(AuditorState)
17
+ .addNode("auditContract", auditContract)
18
+ .addEdge(START, "auditContract")
19
+ .addEdge("auditContract", END)
20
+ .compile();
src/agents/auditor/index.ts DELETED
@@ -1,62 +0,0 @@
1
- import { AIMessage, SystemMessage, type ToolMessage } from "@langchain/core/messages";
2
- import { type ConditionalEdgeRouter, END, type GraphNode, START, StateGraph } from "@langchain/langgraph";
3
- import { model } from "./model";
4
- import { MessagesState } from "./state";
5
- import { searchTool } from "./tools/search-tool";
6
-
7
- const modelWithTools = model.bindTools([searchTool]);
8
-
9
- const llmCall: GraphNode<typeof MessagesState> = async (state) => {
10
- return {
11
- messages: [
12
- await modelWithTools.invoke([
13
- new SystemMessage("You are a helpful assistant tasked with performing arithmetic on a set of inputs."),
14
- ...state.messages,
15
- ]),
16
- ],
17
- llmCalls: 1,
18
- };
19
- };
20
-
21
- const toolNode: GraphNode<typeof MessagesState> = async (state) => {
22
- const lastMessage = state.messages.at(-1);
23
-
24
- if (lastMessage == null || !AIMessage.isInstance(lastMessage)) {
25
- return { messages: [] };
26
- }
27
-
28
- const result: ToolMessage[] = [];
29
- for (const toolCall of lastMessage.tool_calls ?? []) {
30
- const _toolName = toolCall.name;
31
- const tool = searchTool;
32
- const observation = await tool.invoke(toolCall);
33
- result.push(observation);
34
- }
35
-
36
- return { messages: result };
37
- };
38
-
39
- const shouldContinue: ConditionalEdgeRouter<typeof MessagesState, {}, "toolNode"> = (state) => {
40
- const lastMessage = state.messages.at(-1);
41
-
42
- // Check if it's an AIMessage before accessing tool_calls
43
- if (!lastMessage || !AIMessage.isInstance(lastMessage)) {
44
- return END;
45
- }
46
-
47
- // If the LLM makes a tool call, then perform an action
48
- if (lastMessage.tool_calls?.length) {
49
- return "toolNode";
50
- }
51
-
52
- // Otherwise, we stop (reply to the user)
53
- return END;
54
- };
55
-
56
- export const agent = new StateGraph(MessagesState)
57
- .addNode("llmCall", llmCall)
58
- .addNode("toolNode", toolNode)
59
- .addEdge(START, "llmCall")
60
- .addConditionalEdges("llmCall", shouldContinue, ["toolNode", END])
61
- .addEdge("toolNode", "llmCall")
62
- .compile();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/agents/auditor/model.ts CHANGED
@@ -1,5 +1,5 @@
1
  import { ChatOpenRouter } from "@langchain/openrouter";
2
 
3
- export const model = new ChatOpenRouter({
4
- model: "claude-3-7-sonnet-latest",
5
  });
 
1
  import { ChatOpenRouter } from "@langchain/openrouter";
2
 
3
+ export const auditorModel = new ChatOpenRouter({
4
+ model: "moonshotai/kimi-k2.6",
5
  });
src/agents/auditor/state.ts CHANGED
@@ -1,7 +1,7 @@
1
- import { MessagesValue, ReducedValue, StateSchema } from "@langchain/langgraph";
2
  import { z } from "zod";
3
 
4
- export const MessagesState = new StateSchema({
5
- messages: MessagesValue,
6
- llmCalls: new ReducedValue(z.number().default(0), { reducer: (x, y) => x + y }),
7
  });
 
1
+ import { StateSchema } from "@langchain/langgraph";
2
  import { z } from "zod";
3
 
4
+ export const AuditorState = new StateSchema({
5
+ solidityFile: z.string().default(""),
6
+ vulnerabilities: z.array(z.record(z.string(), z.any())).default([]),
7
  });
src/agents/auditor/tools/search-tool.ts DELETED
@@ -1,18 +0,0 @@
1
- import { tool } from "langchain";
2
- import { z } from "zod";
3
-
4
- export const searchTool = tool(
5
- async ({ query }) => {
6
- if (query.toLowerCase().includes("sf") || query.toLowerCase().includes("san francisco")) {
7
- return "It's 60 degrees and foggy.";
8
- }
9
- return "It's 90 degrees and sunny.";
10
- },
11
- {
12
- name: "search",
13
- description: "Call to surf the web.",
14
- schema: z.object({
15
- query: z.string().describe("The query to use in your search."),
16
- }),
17
- },
18
- );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/agents/auditor/tools/slither-tool.ts ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { tool } from "langchain";
2
+ import { z } from "zod";
3
+
4
+ export const slitherTool = tool(
5
+ async (_input) => {
6
+ return [];
7
+ },
8
+ {
9
+ name: "slither",
10
+ description: "Run slither static analysis on a Solidity contract.",
11
+ schema: z.object({
12
+ solidityFile: z.string().describe("The Solidity source code to analyze."),
13
+ }),
14
+ },
15
+ );
src/agents/coder/agent.ts ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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();
src/agents/coder/state.ts ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ import { StateSchema } from "@langchain/langgraph";
2
+ import { z } from "zod";
3
+
4
+ export const CoderState = new StateSchema({
5
+ requirements: z.array(z.string()).default([]),
6
+ contract: z.string().default(""),
7
+ });
src/agents/tester/agent.ts ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { END, type GraphNode, START, StateGraph } from "@langchain/langgraph";
2
+
3
+ import { TesterState } from "./state.ts";
4
+
5
+ const runTests: GraphNode<typeof TesterState> = async (_state) => {
6
+ return { results: [] };
7
+ };
8
+
9
+ export const testerAgent = new StateGraph(TesterState)
10
+ .addNode("runTests", runTests)
11
+ .addEdge(START, "runTests")
12
+ .addEdge("runTests", END)
13
+ .compile();
src/agents/tester/state.ts ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ import { StateSchema } from "@langchain/langgraph";
2
+ import { z } from "zod";
3
+
4
+ export const TesterState = new StateSchema({
5
+ solidityFiles: z.array(z.string()).default([]),
6
+ vulnerability: z.record(z.string(), z.any()).default({}),
7
+ results: z.array(z.any()).default([]),
8
+ });
src/index.ts CHANGED
@@ -1,3 +1,22 @@
1
  import "dotenv/config";
2
 
3
- console.log("TALP 1");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import "dotenv/config";
2
 
3
+ import { auditorAgent } from "./agents/auditor/agent.ts";
4
+ import { coderAgent } from "./agents/coder/agent.ts";
5
+ import { testerAgent } from "./agents/tester/agent.ts";
6
+
7
+ const requirements = ["ERC20 token", "pausable", "ownable"];
8
+
9
+ const coderResult = await coderAgent.invoke({ requirements });
10
+ console.log("======= Coder =======");
11
+ console.log(coderResult.contract);
12
+
13
+ const auditorResult = await auditorAgent.invoke({ solidityFile: coderResult.contract });
14
+ console.log("\n======= Auditor =======");
15
+ console.log(auditorResult.vulnerabilities);
16
+
17
+ const testerResult = await testerAgent.invoke({
18
+ solidityFiles: [coderResult.contract],
19
+ vulnerability: auditorResult.vulnerabilities[0] ?? {},
20
+ });
21
+ console.log("\n======= Tester =======");
22
+ console.log(testerResult.results);
tsconfig.json CHANGED
@@ -6,6 +6,7 @@
6
  "compilerOptions": {
7
  "rootDir": "./src",
8
  "outDir": "./dist",
 
9
  "module": "nodenext",
10
  "target": "esnext",
11
  "types": [
 
6
  "compilerOptions": {
7
  "rootDir": "./src",
8
  "outDir": "./dist",
9
+ "moduleResolution": "nodenext",
10
  "module": "nodenext",
11
  "target": "esnext",
12
  "types": [