Extending the Solana Agent Kit with custom tools allows you to add specialized functionalities tailored to your needs. This guide walks you through creating and integrating a new tool into the existing framework.
Overview
Add supporting functions in SolanaAgentKit
Implement the Langchain tool class
Export the Langchain tool
Export your protocol’s langchain tools (if not already exported)
Define Action class for given tool
Implementation Guide
Create a new TypeScript file in the src/tools/your_protocol
directory for your tool (e.g., custom_tool.ts
). If the src/tools/your_protocol
directory does not exist, create it.
src/tools/index.ts
Copy export * from "./squads";
export * from "./jupiter";
export * from "./your_protocol"; // Add your protocol here if it's not already in the list
src/agent/index.ts
Copy export class SolanaAgentKit {
// ... existing code ...
async customFunction(input: string): Promise<string> {
// Implement your custom functionality
return `Processed input: ${input}`;
}
}
src/langchain/your_protocol/custom_tool.ts
Copy import { Tool } from "langchain/tools";
import { SolanaAgentKit } from "../../agent";
export class CustomTool extends Tool {
name = "custom_tool";
description = "Description of what the custom tool does.";
constructor(private solanaKit: SolanaAgentKit) {
super();
}
protected async _call(input: string): Promise<string> {
try {
const result = await this.solanaKit.customFunction(input);
return JSON.stringify({
status: "success",
message: "Custom tool executed successfully",
data: result,
});
} catch (error: any) {
return JSON.stringify({
status: "error",
message: error.message,
code: error.code || "UNKNOWN_ERROR",
});
}
}
}
src/langchain/your_protocol/index.ts
Copy export * from "./custom_tool";
src/langchain/index.ts
Copy export * from "./tiplink";
export * from "./your_protocol"; // Add your protocol here if it's not already in the list
src/actions/your_protocol/custom_action.ts
Copy import { Action } from "../../types/action";
import { SolanaAgentKit } from "../../agent";
import { z } from "zod";
import { custom_tool } from "../../tools";
const customAction: Action = {
name: "CUSTOM_ACTION",
similes: ["custom tool"],
description: "Description of what the custom tool does.",
examples: [
{
input: {},
output: {
status: "success",
message: "Custom tool executed successfully",
data: result,
},
explanation: "Custom tool executed successfully",
},
],
schema: z.object({
input: z.string(),
}),
handler: async (agent: SolanaAgentKit, input: Record<string, any>) => {
const result = await agent.customFunction(input);
return result;
},
};
src/actions/index.ts
Copy import customAction from "./your_protocol/custom_action";
export const ACTIONS = {
// ... existing actions ...
CUSTOM_ACTION: customAction,
}
Add a code example in the README.md
file.
Copy import { SolanaAgentKit, createSolanaTools } from "solana-agent-kit";
const agent = new SolanaAgentKit(
"your-wallet-private-key-as-base58",
"https://api.mainnet-beta.solana.com",
"your-openai-api-key"
);
const tools = createSolanaTools(agent);
const customTool = tools.find(tool => tool.name === "custom_tool");
if (customTool) {
const result = await customTool._call("your-input");
console.log(result);
}
// or alternatively
const result = await agent.customFunction("your-input"); // assuming you have implemented `customFunction` method in SolanaAgentKit
console.log(result);
Implement robust error handling
Add security checks for sensitive operations
Document your tool’s purpose and usage
Write tests for reliability
Keep tools focused on single responsibilities
Here’s a complete example of implementing a tool to fetch token prices:
src/tools/fetch_token_price.ts
Copy import { Tool } from "langchain/tools";
import { SolanaAgentKit } from "../agent";
export class FetchTokenPriceTool extends Tool {
name = "fetch_token_price";
description = "Fetches the current price of a specified token.";
constructor(private solanaKit: SolanaAgentKit) {
super();
}
protected async _call(tokenSymbol: string): Promise<string> {
try {
const price = await this.solanaKit.getTokenPrice(tokenSymbol);
return JSON.stringify({
status: "success",
message: `Price fetched successfully for ${tokenSymbol}.`,
data: { token: tokenSymbol, price },
});
} catch (error: any) {
return JSON.stringify({
status: "error",
message: error.message,
code: error.code || "UNKNOWN_ERROR",
});
}
}
}
Add the supporting function to SolanaAgentKit:
src/agent/index.ts
Copy export class SolanaAgentKit {
async getTokenPrice(tokenSymbol: string): Promise<number> {
const mockPrices: { [key: string]: number } = {
SOL: 150,
USDC: 1,
USDT: 1,
BONK: 0.5,
};
if (!mockPrices[tokenSymbol.toUpperCase()]) {
throw new Error(`Price for token symbol ${tokenSymbol} not found.`);
}
return mockPrices[tokenSymbol.toUpperCase()];
}
}
Add Action for given tool:
src/actions/fetch_token_price.ts
Copy import { Action } from "../types/action";
import { SolanaAgentKit } from "../agent";
import { z } from "zod";
import { fetch_token_price } from "../tools";
const fetchTokenPriceAction: Action = {
name: "FETCH_TOKEN_PRICE",
similes: ["fetch token price"],
description: "Fetches the current price of a specified token.",
examples: [
{
input: { tokenSymbol: "SOL" },
output: {
status: "success",
message: "Price fetched successfully for SOL.",
price: 150,
},
explanation: "Fetch the current price of SOL token in USDC",
},
],
schema: z.object({
tokenSymbol: z.string().describe("The symbol of the token to fetch the price for"),
}),
handler: async (agent: SolanaAgentKit, input: Record<string, any>) => {
const price = await agent.getTokenPrice(input.tokenSymbol);
return {
status: "success",
price,
message: `Price fetched successfully for ${input.tokenSymbol}.`,
};
},
};
Then it can be used as such:
Copy import { SolanaAgentKit } from "solana-agent-kit";
const agent = new SolanaAgentKit(
"your-wallet-private-key-as-base58",
"https://api.mainnet-beta.solana.com",
"your-openai-api-key"
);
const result = await agent.getTokenPrice("SOL");
console.log(result);