Uanderson Silva commited on
Commit
f27a135
·
1 Parent(s): 0b3cd21

use different llms for each phase

Browse files
Files changed (2) hide show
  1. src/agents/auditor/agent.ts +7 -5
  2. src/config/llm.ts +18 -11
src/agents/auditor/agent.ts CHANGED
@@ -29,7 +29,9 @@ import { buildRepoTree } from "./tools/repo-tree/tool.ts";
29
  import { analyzeSolidityFile } from "./tools/solidity-analyzer/tool.ts";
30
  import { matchLines } from "./utils.ts";
31
 
32
- const llm = createLLM();
 
 
33
 
34
  const walkDirectory = (dir: string, depth: number, solFiles: string[], docFiles: string[]) => {
35
  if (depth > MAX_DEPTH) return;
@@ -79,7 +81,7 @@ const defineScope: GraphNode<typeof AuditorState> = async (state) => {
79
  logger.info("defineScope: ranking files by importance");
80
 
81
  const RankFilesSchema = z.object({ rankings: z.array(FileRankingSchema) });
82
- const rankingModel = llm.withStructuredOutput(RankFilesSchema);
83
 
84
  const { rankings } = await rankingModel.invoke([
85
  new SystemMessage(RANK_FILES_PROMPT),
@@ -138,7 +140,7 @@ const gatherContext: GraphNode<typeof AuditorState> = async (state) => {
138
  parts.push(analysis);
139
  }
140
 
141
- const model = llm.withStructuredOutput(z.object({ context: z.string() }));
142
  const result = await model.invoke([new SystemMessage(GATHER_CONTEXT_PROMPT), new HumanMessage(parts.join("\n\n"))]);
143
 
144
  logger.debug(`gatherContext: full context:\n${parts.join("\n\n")}`);
@@ -149,7 +151,7 @@ const gatherContext: GraphNode<typeof AuditorState> = async (state) => {
149
  };
150
 
151
  const findVulnerabilities: GraphNode<typeof AuditorState> = async (state) => {
152
- const model = llm.withStructuredOutput(z.object({ findings: z.array(CandidateFindingSchema) }));
153
 
154
  const previousFeedback =
155
  state.judgeReviews.length > 0
@@ -212,7 +214,7 @@ const judgeFindings: GraphNode<typeof AuditorState> = async (state) => {
212
  };
213
  }
214
 
215
- const model = llm.withStructuredOutput(JudgeReviewSchema);
216
 
217
  logger.info(`judgeFindings: reviewing ${state.candidateFindings.length} candidate finding(s) in parallel`);
218
 
 
29
  import { analyzeSolidityFile } from "./tools/solidity-analyzer/tool.ts";
30
  import { matchLines } from "./utils.ts";
31
 
32
+ const llmHaiku = createLLM("anthropic", { model: "claude-haiku-4-5", maxTokens: 20000 });
33
+ const llmOpus = createLLM("anthropic", { model: "claude-opus-4-8", maxTokens: 20000 });
34
+ const llmSonnet = createLLM("anthropic", { model: "claude-sonnet-4-6", maxTokens: 20000 });
35
 
36
  const walkDirectory = (dir: string, depth: number, solFiles: string[], docFiles: string[]) => {
37
  if (depth > MAX_DEPTH) return;
 
81
  logger.info("defineScope: ranking files by importance");
82
 
83
  const RankFilesSchema = z.object({ rankings: z.array(FileRankingSchema) });
84
+ const rankingModel = llmHaiku.withStructuredOutput(RankFilesSchema);
85
 
86
  const { rankings } = await rankingModel.invoke([
87
  new SystemMessage(RANK_FILES_PROMPT),
 
140
  parts.push(analysis);
141
  }
142
 
143
+ const model = llmHaiku.withStructuredOutput(z.object({ context: z.string() }));
144
  const result = await model.invoke([new SystemMessage(GATHER_CONTEXT_PROMPT), new HumanMessage(parts.join("\n\n"))]);
145
 
146
  logger.debug(`gatherContext: full context:\n${parts.join("\n\n")}`);
 
151
  };
152
 
153
  const findVulnerabilities: GraphNode<typeof AuditorState> = async (state) => {
154
+ const model = llmOpus.withStructuredOutput(z.object({ findings: z.array(CandidateFindingSchema) }));
155
 
156
  const previousFeedback =
157
  state.judgeReviews.length > 0
 
214
  };
215
  }
216
 
217
+ const model = llmSonnet.withStructuredOutput(JudgeReviewSchema);
218
 
219
  logger.info(`judgeFindings: reviewing ${state.candidateFindings.length} candidate finding(s) in parallel`);
220
 
src/config/llm.ts CHANGED
@@ -5,32 +5,39 @@ import type { BaseChatModel } from "@langchain/core/language_models/chat_models"
5
 
6
  export type LLMProvider = "google" | "openrouter" | "anthropic";
7
 
8
- export function createLLM(overrideProvider?: LLMProvider): BaseChatModel {
 
 
 
 
 
 
9
  const provider = overrideProvider || (process.env.LLM_PROVIDER as LLMProvider) || "openrouter";
10
 
11
  switch (provider) {
12
  case "openrouter":
13
  return new ChatOpenRouter({
14
- model: process.env.OPENROUTER_MODEL || "google/gemini-3.1-flash-lite",
15
- temperature: 0.2,
16
  apiKey: process.env.OPENROUTER_API_KEY,
17
- maxTokens: 4096,
18
  });
19
 
20
-
21
  case "anthropic":
22
  return new ChatAnthropic({
23
- model: process.env.ANTHROPIC_MODEL || "claude-sonnet-4-6",
24
- temperature: 0.2,
25
- maxTokens: 4096,
 
26
  });
 
27
  case "google":
28
  default:
29
  return new ChatGoogleGenerativeAI({
30
  apiKey: process.env.GOOGLE_API_KEY || "",
31
- model: process.env.MODEL_NAME || "gemini-2.5-flash",
32
- temperature: 0.2,
33
- maxOutputTokens: 4096,
34
  });
35
  }
36
  }
 
5
 
6
  export type LLMProvider = "google" | "openrouter" | "anthropic";
7
 
8
+ export interface LLMOptions {
9
+ model?: string;
10
+ temperature?: number;
11
+ maxTokens?: number;
12
+ }
13
+
14
+ export function createLLM(overrideProvider?: LLMProvider, options?: LLMOptions): BaseChatModel {
15
  const provider = overrideProvider || (process.env.LLM_PROVIDER as LLMProvider) || "openrouter";
16
 
17
  switch (provider) {
18
  case "openrouter":
19
  return new ChatOpenRouter({
20
+ model: options?.model || process.env.OPENROUTER_MODEL || "google/gemini-3.1-flash-lite",
21
+ temperature: options?.temperature ?? 0.2,
22
  apiKey: process.env.OPENROUTER_API_KEY,
23
+ maxTokens: options?.maxTokens ?? 4096,
24
  });
25
 
 
26
  case "anthropic":
27
  return new ChatAnthropic({
28
+ model: options?.model || process.env.ANTHROPIC_MODEL || "claude-sonnet-4-6",
29
+ temperature: options?.temperature ?? 0.2,
30
+ apiKey: process.env.ANTHROPIC_API_KEY,
31
+ maxTokens: options?.maxTokens ?? 4096,
32
  });
33
+
34
  case "google":
35
  default:
36
  return new ChatGoogleGenerativeAI({
37
  apiKey: process.env.GOOGLE_API_KEY || "",
38
+ model: options?.model || process.env.MODEL_NAME || "gemini-2.5-flash",
39
+ temperature: options?.temperature ?? 0.2,
40
+ maxOutputTokens: options?.maxTokens ?? 4096,
41
  });
42
  }
43
  }