mirror of
https://github.com/d0zingcat/solana-agent-kit.git
synced 2026-05-24 07:36:45 +00:00
added write functionalities ie, swap and transfer
This commit is contained in:
@@ -1,8 +1,7 @@
|
||||
import { createReactAgent } from "@langchain/langgraph/prebuilt";
|
||||
import { gpt4o } from "../utils/model.js";
|
||||
import { solanaAgentState } from "../utils/state.js";
|
||||
import { gpt4o } from "../utils/model";
|
||||
import { solanaAgentState } from "../utils/state";
|
||||
import { TavilySearchResults } from "@langchain/community/tools/tavily_search";
|
||||
import { HumanMessage } from "@langchain/core/messages";
|
||||
|
||||
// Initialize tools array
|
||||
const searchTools = [];
|
||||
@@ -12,7 +11,7 @@ if (process.env.TAVILY_API_KEY) {
|
||||
searchTools.push(new TavilySearchResults());
|
||||
}
|
||||
|
||||
export const generalAgent = createReactAgent({
|
||||
const generalAgent = createReactAgent({
|
||||
llm: gpt4o,
|
||||
tools: searchTools,
|
||||
});
|
||||
@@ -24,9 +23,3 @@ export const generalistNode = async (state: typeof solanaAgentState.State) => {
|
||||
|
||||
return { messages: [...result.messages] };
|
||||
};
|
||||
|
||||
const messages = [new HumanMessage("What is the best way to buy SOL?")];
|
||||
|
||||
const result = await generalAgent.invoke({ messages });
|
||||
|
||||
console.log(result.messages);
|
||||
|
||||
23
examples/agent-kit-langgraph/src/agents/manager.ts
Normal file
23
examples/agent-kit-langgraph/src/agents/manager.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { prompt, parser } from "../prompts/manager";
|
||||
import { RunnableSequence } from "@langchain/core/runnables";
|
||||
import { solanaAgentState } from "../utils/state";
|
||||
import { gpt4o } from "../utils/model";
|
||||
|
||||
const chain = RunnableSequence.from([prompt, gpt4o, parser]);
|
||||
|
||||
export const managerNode = async (state: typeof solanaAgentState.State) => {
|
||||
const { messages } = state;
|
||||
|
||||
const result = await chain.invoke({
|
||||
formatInstructions: parser.getFormatInstructions(),
|
||||
messages: messages,
|
||||
});
|
||||
|
||||
const { isSolanaReadQuery, isSolanaWriteQuery, isGeneralQuery } = result;
|
||||
|
||||
return {
|
||||
isSolanaReadQuery,
|
||||
isSolanaWriteQuery,
|
||||
isGeneralQuery,
|
||||
};
|
||||
};
|
||||
25
examples/agent-kit-langgraph/src/agents/transferOrSwap.ts
Normal file
25
examples/agent-kit-langgraph/src/agents/transferOrSwap.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { gpt4o } from "../utils/model";
|
||||
import { agentKit } from "../utils/solanaAgent";
|
||||
import { solanaAgentState } from "../utils/state";
|
||||
import { createReactAgent } from "@langchain/langgraph/prebuilt";
|
||||
import { SolanaTransferTool } from "solana-agent-kit/dist/langchain";
|
||||
import { transferSwapPrompt } from "../prompts/transferSwap";
|
||||
import { swapTool } from "../tools/swap";
|
||||
|
||||
const transferOrSwapAgent = createReactAgent({
|
||||
stateModifier: transferSwapPrompt,
|
||||
llm: gpt4o,
|
||||
tools: [new SolanaTransferTool(agentKit), swapTool],
|
||||
});
|
||||
|
||||
export const transferSwapNode = async (
|
||||
state: typeof solanaAgentState.State,
|
||||
) => {
|
||||
const { messages } = state;
|
||||
|
||||
const result = await transferOrSwapAgent.invoke({
|
||||
messages,
|
||||
});
|
||||
|
||||
return result;
|
||||
};
|
||||
5
examples/agent-kit-langgraph/src/helper/examples.ts
Normal file
5
examples/agent-kit-langgraph/src/helper/examples.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import { HumanMessage } from "@langchain/core/messages";
|
||||
|
||||
export const generalQuestion = [
|
||||
new HumanMessage("Who is the president of Ecuador?"),
|
||||
];
|
||||
50
examples/agent-kit-langgraph/src/helper/tokenList.ts
Normal file
50
examples/agent-kit-langgraph/src/helper/tokenList.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
export const tokenList = [
|
||||
{
|
||||
name: "USDC",
|
||||
ticker: "USDC",
|
||||
decimal: 6,
|
||||
mintAddress: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
|
||||
},
|
||||
{
|
||||
name: "USDT",
|
||||
ticker: "USDT",
|
||||
decimal: 6,
|
||||
mintAddress: "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB",
|
||||
},
|
||||
{
|
||||
name: "USDS",
|
||||
ticker: "USDS",
|
||||
decimal: 6,
|
||||
mintAddress: "USDSwr9ApdHk5bvJKMjzff41FfuX8bSxdKcR81vTwcA",
|
||||
},
|
||||
{
|
||||
name: "SOL",
|
||||
ticker: "SOL",
|
||||
decimal: 9,
|
||||
mintAddress: "So11111111111111111111111111111111111111112",
|
||||
},
|
||||
{
|
||||
name: "jitoSOL",
|
||||
ticker: "jitoSOL",
|
||||
decimal: 9,
|
||||
mintAddress: "J1toso1uCk3RLmjorhTtrVwY9HJ7X8V9yYac6Y7kGCPn",
|
||||
},
|
||||
{
|
||||
name: "bSOL",
|
||||
ticker: "bSOL",
|
||||
decimal: 9,
|
||||
mintAddress: "bSo13r4TkiE4KumL71LsHTPpL2euBYLFx6h9HP3piy1",
|
||||
},
|
||||
{
|
||||
name: "mSOL",
|
||||
ticker: "mSOL",
|
||||
decimal: 9,
|
||||
mintAddress: "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So",
|
||||
},
|
||||
{
|
||||
name: "BONK",
|
||||
ticker: "BONK",
|
||||
decimal: 9,
|
||||
mintAddress: "DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263",
|
||||
},
|
||||
];
|
||||
@@ -1,6 +1,25 @@
|
||||
import { StateGraph } from "@langchain/langgraph";
|
||||
import { solanaAgentState } from "./utils/state";
|
||||
import { generalistNode } from "./agents/generalAgent";
|
||||
import { transferSwapNode } from "./agents/transferOrSwap";
|
||||
import { managerNode } from "./agents/manager";
|
||||
import { START, END } from "@langchain/langgraph";
|
||||
import { managerRouter } from "./utils/route";
|
||||
import { HumanMessage } from "@langchain/core/messages";
|
||||
|
||||
const workflow = new StateGraph(solanaAgentState);
|
||||
const workflow = new StateGraph(solanaAgentState)
|
||||
.addNode("generalist", generalistNode)
|
||||
.addNode("manager", managerNode)
|
||||
.addNode("transferSwap", transferSwapNode)
|
||||
.addEdge(START, "manager")
|
||||
.addConditionalEdges("manager", managerRouter)
|
||||
.addEdge("generalist", END)
|
||||
.addEdge("transferSwap", END);
|
||||
|
||||
export const graph = workflow.compile();
|
||||
|
||||
const result = await graph.invoke({
|
||||
messages: [new HumanMessage("swap 0.1 usdc to sol")],
|
||||
});
|
||||
|
||||
console.log(result);
|
||||
|
||||
48
examples/agent-kit-langgraph/src/prompts/manager.ts
Normal file
48
examples/agent-kit-langgraph/src/prompts/manager.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import { StructuredOutputParser } from "@langchain/core/output_parsers";
|
||||
import { z } from "zod";
|
||||
import { PromptTemplate } from "@langchain/core/prompts";
|
||||
|
||||
export const parser = StructuredOutputParser.fromZodSchema(
|
||||
z.object({
|
||||
isSolanaReadQuery: z
|
||||
.boolean()
|
||||
.describe("Query requires reading data from Solana blockchain"),
|
||||
isSolanaWriteQuery: z
|
||||
.boolean()
|
||||
.describe("Query requires writing/modifying data on Solana blockchain"),
|
||||
isGeneralQuery: z
|
||||
.boolean()
|
||||
.describe("Query is about non-blockchain topics"),
|
||||
}),
|
||||
);
|
||||
|
||||
export const prompt = PromptTemplate.fromTemplate(
|
||||
`
|
||||
You are the Chief Routing Officer for a multi-blockchain agent network. Your role is to:
|
||||
1. Analyze and classify incoming queries
|
||||
2. Determine if the query requires Solana read operations, write operations, or is general
|
||||
|
||||
Format your response according to:
|
||||
{formatInstructions}
|
||||
|
||||
Classification Guidelines:
|
||||
- Solana Read Operations include:
|
||||
* Checking account balances
|
||||
* Viewing NFT metadata
|
||||
* Getting program data
|
||||
* Querying transaction history
|
||||
* Checking token prices or holdings
|
||||
- Solana Write Operations include:
|
||||
* Creating or updating programs
|
||||
* Sending tokens or SOL
|
||||
* Minting NFTs
|
||||
* Creating accounts
|
||||
* Any transaction that modifies blockchain state
|
||||
- General queries include:
|
||||
* Non-blockchain topics
|
||||
* Internet searches
|
||||
* General knowledge questions
|
||||
|
||||
\n {messages} \n
|
||||
`,
|
||||
);
|
||||
43
examples/agent-kit-langgraph/src/prompts/transferSwap.ts
Normal file
43
examples/agent-kit-langgraph/src/prompts/transferSwap.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import {
|
||||
ChatPromptTemplate,
|
||||
MessagesPlaceholder,
|
||||
} from "@langchain/core/prompts";
|
||||
import { tokenList } from "../helper/tokenList";
|
||||
|
||||
// Convert token list to a more readable format for the prompt
|
||||
const formattedTokenList = tokenList
|
||||
.map(
|
||||
(token) =>
|
||||
`- ${token.name} (${token.ticker}) - Decimals: ${token.decimal} - Address: ${token.mintAddress}`,
|
||||
)
|
||||
.join("\n ");
|
||||
|
||||
export const transferSwapPrompt = ChatPromptTemplate.fromMessages([
|
||||
[
|
||||
"system",
|
||||
`You are an agent that is an expert in Solana transactions, specialized in token transfers and swaps. You can execute these transactions using the available tools based on user input.
|
||||
|
||||
When processing token amounts:
|
||||
1. Use EXACTLY the decimal amount specified by the user without any modifications
|
||||
2. Do not round or adjust the numbers
|
||||
3. Maintain precise decimal places as provided in the user input
|
||||
|
||||
For transfers:
|
||||
- User must specify the token, amount, and recipient address
|
||||
- The same token will be used for input and output
|
||||
|
||||
For swaps:
|
||||
- User must specify the input token, output token, and amount to swap
|
||||
- Input and output tokens must be different
|
||||
- Select tokens from this list of supported tokens:
|
||||
|
||||
${formattedTokenList}
|
||||
|
||||
Example amounts:
|
||||
If you say "0.01 SOL", I will use exactly 0.01 (not 0.010 or 0.0100)
|
||||
If you say "1.234 USDC", I will use exactly 1.234 (not 1.23 or 1.2340)
|
||||
For swaps, have the slippage be 200 bps
|
||||
`,
|
||||
],
|
||||
new MessagesPlaceholder("messages"),
|
||||
]);
|
||||
45
examples/agent-kit-langgraph/src/tools/swap.ts
Normal file
45
examples/agent-kit-langgraph/src/tools/swap.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import { agentKit } from "../utils/solanaAgent";
|
||||
import { tool } from "@langchain/core/tools";
|
||||
import { z } from "zod";
|
||||
import { PublicKey } from "@solana/web3.js";
|
||||
|
||||
export const swapTool = tool(
|
||||
async ({ outputMint, inputAmount, inputMint, inputDecimal }) => {
|
||||
try {
|
||||
const inputAmountWithDecimals = inputAmount * 10 ** inputDecimal;
|
||||
const outputMintAddress = new PublicKey(outputMint);
|
||||
const inputMintAddress = new PublicKey(inputMint);
|
||||
|
||||
console.log(inputAmountWithDecimals, outputMintAddress, inputMintAddress);
|
||||
const tx = await agentKit.trade(
|
||||
outputMintAddress,
|
||||
inputAmountWithDecimals,
|
||||
inputMintAddress,
|
||||
200,
|
||||
);
|
||||
return tx;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return "error";
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "swap",
|
||||
description:
|
||||
"call to swap/trade tokens from one token to the other using Jupiter exchange",
|
||||
schema: z.object({
|
||||
outputMint: z
|
||||
.string()
|
||||
.describe("The mint address of destination token to be swapped to"),
|
||||
inputAmount: z
|
||||
.number()
|
||||
.describe(
|
||||
"the input amount of the token to be swapped without adding any decimals",
|
||||
),
|
||||
inputMint: z.string().describe("The mint address of the origin token "),
|
||||
inputDecimal: z
|
||||
.number()
|
||||
.describe("The decimal of the input token that is being traded"),
|
||||
}),
|
||||
},
|
||||
);
|
||||
@@ -0,0 +1,14 @@
|
||||
import { solanaAgentState } from "./state";
|
||||
import { END } from "@langchain/langgraph";
|
||||
|
||||
export const managerRouter = (state: typeof solanaAgentState.State) => {
|
||||
const { isSolanaReadQuery, isSolanaWriteQuery, isGeneralQuery } = state;
|
||||
|
||||
if (isGeneralQuery) {
|
||||
return "generalist";
|
||||
} else if (isSolanaWriteQuery) {
|
||||
return "transferSwap";
|
||||
} else {
|
||||
return END;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { SolanaAgentKit } from "solana-agent-kit";
|
||||
import { SolanaAgentKit, createSolanaTools } from "solana-agent-kit";
|
||||
|
||||
export const agentKit = new SolanaAgentKit(
|
||||
process.env.SOLANA_PRIVATE_KEY!,
|
||||
process.env.RPC_URL!,
|
||||
process.env.OPENAI_API_KEY!,
|
||||
);
|
||||
|
||||
export const solanaTools = createSolanaTools(agentKit);
|
||||
|
||||
Reference in New Issue
Block a user