fix: lint

This commit is contained in:
michaelessiet
2025-01-03 18:22:32 +01:00
parent a8952f3308
commit c2bf6191ff
13 changed files with 1604 additions and 1598 deletions

View File

@@ -5,24 +5,24 @@ import { createReactAgent } from "@langchain/langgraph/prebuilt";
import { SolanaAgentKit, createSolanaTools } from "solana-agent-kit";
const llm = new ChatOpenAI({
temperature: 0.7,
model: "gpt-4o-mini",
temperature: 0.7,
model: "gpt-4o-mini",
});
const solanaAgent = new SolanaAgentKit(
process.env.SOLANA_PRIVATE_KEY!,
process.env.RPC_URL,
process.env.OPENAI_API_KEY!,
process.env.SOLANA_PRIVATE_KEY!,
process.env.RPC_URL,
process.env.OPENAI_API_KEY!,
);
const tools = createSolanaTools(solanaAgent);
const memory = new MemorySaver();
const agent = createReactAgent({
llm,
tools,
checkpointSaver: memory,
messageModifier: `
llm,
tools,
checkpointSaver: memory,
messageModifier: `
You are a helpful agent that can interact onchain using the Solana Agent Kit. You are
empowered to interact onchain using your tools. If you ever need funds, you can request them from the
faucet. If not, you can provide your wallet details and request funds from the user. If there is a 5XX
@@ -34,38 +34,38 @@ const agent = createReactAgent({
});
export async function POST(req: NextRequest) {
try {
const body = await req.json();
const messages = body.messages ?? [];
try {
const body = await req.json();
const messages = body.messages ?? [];
const eventStream = agent.streamEvents(
{
messages,
},
{
version: "v2",
configurable: {
thread_id: "Solana Agent Kit!",
},
},
);
const eventStream = agent.streamEvents(
{
messages,
},
{
version: "v2",
configurable: {
thread_id: "Solana Agent Kit!",
},
},
);
const textEncoder = new TextEncoder();
const transformStream = new ReadableStream({
async start(controller) {
for await (const { event, data } of eventStream) {
if (event === "on_chat_model_stream") {
if (!!data.chunk.content) {
controller.enqueue(textEncoder.encode(data.chunk.content));
}
}
}
controller.close();
},
});
const textEncoder = new TextEncoder();
const transformStream = new ReadableStream({
async start(controller) {
for await (const { event, data } of eventStream) {
if (event === "on_chat_model_stream") {
if (data.chunk.content) {
controller.enqueue(textEncoder.encode(data.chunk.content));
}
}
}
controller.close();
},
});
return new Response(transformStream);
} catch (e: any) {
return NextResponse.json({ error: e.message }, { status: e.status ?? 500 });
}
return new Response(transformStream);
} catch (e: any) {
return NextResponse.json({ error: e.message }, { status: e.status ?? 500 });
}
}

View File

@@ -537,4 +537,4 @@ const executor = await initializeAgentExecutorWithOptions(tools, llm, {
},
});
\`\`\`
`;
`;

View File

@@ -2,29 +2,29 @@ import { marked } from "marked";
import DOMPurify from "isomorphic-dompurify";
interface MarkedOptions {
gfm: boolean;
breaks: boolean;
headerIds: boolean;
mangle: false;
highlight?: (code: string, lang: string) => string;
gfm: boolean;
breaks: boolean;
headerIds: boolean;
mangle: false;
highlight?: (code: string, lang: string) => string;
}
// Configure marked options
const markedOptions: MarkedOptions = {
gfm: true, // GitHub Flavored Markdown
breaks: true, // Convert \n to <br>
headerIds: true, // Add ids to headers
mangle: false, // Don't escape HTML
highlight: function (code: string, lang: string): string {
// You can add syntax highlighting here if needed
return code;
},
gfm: true, // GitHub Flavored Markdown
breaks: true, // Convert \n to <br>
headerIds: true, // Add ids to headers
mangle: false, // Don't escape HTML
highlight: function (code: string, lang: string): string {
// You can add syntax highlighting here if needed
return code;
},
};
marked.setOptions(markedOptions);
// Basic markdown to HTML conversion with sanitization
export default function markdownToHtml(markdown: string) {
const rawHtml = marked.parse(markdown);
return DOMPurify.sanitize(rawHtml as string);
const rawHtml = marked.parse(markdown);
return DOMPurify.sanitize(rawHtml as string);
}

View File

@@ -10,8 +10,8 @@
"test": "ts-node test/index.ts",
"test:vercel-ai": "ts-node test/agent_sdks/vercel_ai.ts",
"generate": "ts-node src/utils/keypair.ts",
"lint": "eslint . --ext .ts,.json",
"lint:fix": "eslint . --ext .ts,.json --fix",
"lint": "eslint . --ext .ts",
"lint:fix": "eslint . --ext .ts --fix",
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\""
},
"engines": {

View File

@@ -87,7 +87,7 @@ const createOrcaSingleSidedWhirlpoolAction: Action = {
const otherTokenMint = new PublicKey(input.otherTokenMint);
const initialPrice = new Decimal(input.initialPrice);
const maxPrice = new Decimal(input.maxPrice);
const feeTier = input.feeTier
const feeTier = input.feeTier;
// Create the whirlpool
const signature = await orcaCreateSingleSidedLiquidityPool(

View File

@@ -4,26 +4,26 @@ import { get_wallet_address } from "../tools";
import { Action } from "../types/action";
const getWalletAddressAction: Action = {
name: "GET_WALLET_ADDRESS",
similes: ["wallet address", "address", "wallet"],
description: "Get wallet address of the agent",
examples: [
[
{
input: {},
output: {
status: "success",
address: "0x1234567890abcdef",
},
explanation: "The agent's wallet address is 0x1234567890abcdef",
},
],
],
schema: z.object({}),
handler: async (agent: SolanaAgentKit) => ({
status: "success",
address: get_wallet_address(agent),
}),
name: "GET_WALLET_ADDRESS",
similes: ["wallet address", "address", "wallet"],
description: "Get wallet address of the agent",
examples: [
[
{
input: {},
output: {
status: "success",
address: "0x1234567890abcdef",
},
explanation: "The agent's wallet address is 0x1234567890abcdef",
},
],
],
schema: z.object({}),
handler: async (agent: SolanaAgentKit) => ({
status: "success",
address: get_wallet_address(agent),
}),
};
export default getWalletAddressAction;

View File

@@ -29,36 +29,36 @@ import launchPumpfunTokenAction from "./launchPumpfunToken";
import getWalletAddressAction from "./getWalletAddress";
export const ACTIONS = {
WALLET_ADDRESS_ACTION: getWalletAddressAction,
DEPLOY_TOKEN_ACTION: deployTokenAction,
BALANCE_ACTION: balanceAction,
TRANSFER_ACTION: transferAction,
DEPLOY_COLLECTION_ACTION: deployCollectionAction,
MINT_NFT_ACTION: mintNFTAction,
TRADE_ACTION: tradeAction,
REQUEST_FUNDS_ACTION: requestFundsAction,
RESOLVE_DOMAIN_ACTION: resolveDomainAction,
GET_TOKEN_DATA_ACTION: getTokenDataAction,
GET_TPS_ACTION: getTPSAction,
FETCH_PRICE_ACTION: fetchPriceAction,
STAKE_WITH_JUP_ACTION: stakeWithJupAction,
REGISTER_DOMAIN_ACTION: registerDomainAction,
LEND_ASSET_ACTION: lendAssetAction,
CREATE_GIBWORK_TASK_ACTION: createGibworkTaskAction,
RESOLVE_SOL_DOMAIN_ACTION: resolveSolDomainAction,
PYTH_FETCH_PRICE_ACTION: pythFetchPriceAction,
GET_OWNED_DOMAINS_FOR_TLD_ACTION: getOwnedDomainsForTLDAction,
GET_PRIMARY_DOMAIN_ACTION: getPrimaryDomainAction,
GET_ALL_DOMAINS_TLDS_ACTION: getAllDomainsTLDsAction,
GET_OWNED_ALL_DOMAINS_ACTION: getOwnedAllDomainsAction,
CREATE_IMAGE_ACTION: createImageAction,
GET_MAIN_ALL_DOMAINS_DOMAIN_ACTION: getMainAllDomainsDomainAction,
GET_ALL_REGISTERED_ALL_DOMAINS_ACTION: getAllRegisteredAllDomainsAction,
RAYDIUM_CREATE_CPMM_ACTION: raydiumCreateCpmmAction,
RAYDIUM_CREATE_AMM_V4_ACTION: raydiumCreateAmmV4Action,
CREATE_ORCA_SINGLE_SIDED_WHIRLPOOL_ACTION:
createOrcaSingleSidedWhirlpoolAction,
LAUNCH_PUMPFUN_TOKEN_ACTION: launchPumpfunTokenAction,
WALLET_ADDRESS_ACTION: getWalletAddressAction,
DEPLOY_TOKEN_ACTION: deployTokenAction,
BALANCE_ACTION: balanceAction,
TRANSFER_ACTION: transferAction,
DEPLOY_COLLECTION_ACTION: deployCollectionAction,
MINT_NFT_ACTION: mintNFTAction,
TRADE_ACTION: tradeAction,
REQUEST_FUNDS_ACTION: requestFundsAction,
RESOLVE_DOMAIN_ACTION: resolveDomainAction,
GET_TOKEN_DATA_ACTION: getTokenDataAction,
GET_TPS_ACTION: getTPSAction,
FETCH_PRICE_ACTION: fetchPriceAction,
STAKE_WITH_JUP_ACTION: stakeWithJupAction,
REGISTER_DOMAIN_ACTION: registerDomainAction,
LEND_ASSET_ACTION: lendAssetAction,
CREATE_GIBWORK_TASK_ACTION: createGibworkTaskAction,
RESOLVE_SOL_DOMAIN_ACTION: resolveSolDomainAction,
PYTH_FETCH_PRICE_ACTION: pythFetchPriceAction,
GET_OWNED_DOMAINS_FOR_TLD_ACTION: getOwnedDomainsForTLDAction,
GET_PRIMARY_DOMAIN_ACTION: getPrimaryDomainAction,
GET_ALL_DOMAINS_TLDS_ACTION: getAllDomainsTLDsAction,
GET_OWNED_ALL_DOMAINS_ACTION: getOwnedAllDomainsAction,
CREATE_IMAGE_ACTION: createImageAction,
GET_MAIN_ALL_DOMAINS_DOMAIN_ACTION: getMainAllDomainsDomainAction,
GET_ALL_REGISTERED_ALL_DOMAINS_ACTION: getAllRegisteredAllDomainsAction,
RAYDIUM_CREATE_CPMM_ACTION: raydiumCreateCpmmAction,
RAYDIUM_CREATE_AMM_V4_ACTION: raydiumCreateAmmV4Action,
CREATE_ORCA_SINGLE_SIDED_WHIRLPOOL_ACTION:
createOrcaSingleSidedWhirlpoolAction,
LAUNCH_PUMPFUN_TOKEN_ACTION: launchPumpfunTokenAction,
};
export type { Action, ActionExample, Handler } from "../types/action";

View File

@@ -85,24 +85,30 @@ export class SolanaAgentKit {
* @deprecated Using openai_api_key directly in constructor is deprecated.
* Please use the new constructor with Config object instead:
* @example
* const agent = new SolanaAgentKit(privateKey, rpcUrl, {
* const agent = new SolanaAgentKit(privateKey, rpcUrl, {
* OPENAI_API_KEY: 'your-key'
* });
*/
constructor(private_key: string, rpc_url: string, openai_api_key: string | null);
constructor(
private_key: string,
rpc_url: string,
openai_api_key: string | null,
);
constructor(private_key: string, rpc_url: string, config: Config);
constructor(
private_key: string,
rpc_url: string,
configOrKey: Config | string | null,
) {
this.connection = new Connection(rpc_url || "https://api.mainnet-beta.solana.com");
this.connection = new Connection(
rpc_url || "https://api.mainnet-beta.solana.com",
);
this.wallet = Keypair.fromSecretKey(bs58.decode(private_key));
this.wallet_address = this.wallet.publicKey;
// Handle both old and new patterns
if (typeof configOrKey === 'string' || configOrKey === null) {
this.config = { OPENAI_API_KEY: configOrKey || '' };
if (typeof configOrKey === "string" || configOrKey === null) {
this.config = { OPENAI_API_KEY: configOrKey || "" };
} else {
this.config = configOrKey;
}

File diff suppressed because it is too large Load Diff

View File

@@ -6,5 +6,5 @@ import { SolanaAgentKit } from "..";
* @returns string
*/
export function get_wallet_address(agent: SolanaAgentKit) {
return agent.wallet_address.toBase58();
return agent.wallet_address.toBase58();
}

View File

@@ -4,22 +4,22 @@ import { executeAction } from "../utils/actionExecutor";
import { ACTIONS } from "../actions";
export function createSolanaTools(
solanaAgentKit: SolanaAgentKit,
solanaAgentKit: SolanaAgentKit,
): Record<string, CoreTool> {
const tools: Record<string, CoreTool> = {};
const actionKeys = Object.keys(ACTIONS);
const tools: Record<string, CoreTool> = {};
const actionKeys = Object.keys(ACTIONS);
for (const key of actionKeys) {
const action = ACTIONS[key as keyof typeof ACTIONS];
tools[key] = tool({
// @ts-expect-error Value matches type however TS still shows error
id: action.name,
description: action.description,
parameters: action.schema,
execute: async (params) =>
await executeAction(action, solanaAgentKit, params),
});
}
for (const key of actionKeys) {
const action = ACTIONS[key as keyof typeof ACTIONS];
tools[key] = tool({
// @ts-expect-error Value matches type however TS still shows error
id: action.name,
description: action.description,
parameters: action.schema,
execute: async (params) =>
await executeAction(action, solanaAgentKit, params),
});
}
return tools;
return tools;
}

View File

@@ -8,191 +8,191 @@ import { createOpenAI } from "@ai-sdk/openai";
dotenv.config();
function validateEnvironment(): void {
const missingVars: string[] = [];
const requiredVars = ["OPENAI_API_KEY", "RPC_URL", "SOLANA_PRIVATE_KEY"];
const missingVars: string[] = [];
const requiredVars = ["OPENAI_API_KEY", "RPC_URL", "SOLANA_PRIVATE_KEY"];
requiredVars.forEach((varName) => {
if (!process.env[varName]) {
missingVars.push(varName);
}
});
requiredVars.forEach((varName) => {
if (!process.env[varName]) {
missingVars.push(varName);
}
});
if (missingVars.length > 0) {
console.error("Error: Required environment variables are not set");
missingVars.forEach((varName) => {
console.error(`${varName}=your_${varName.toLowerCase()}_here`);
});
process.exit(1);
}
if (missingVars.length > 0) {
console.error("Error: Required environment variables are not set");
missingVars.forEach((varName) => {
console.error(`${varName}=your_${varName.toLowerCase()}_here`);
});
process.exit(1);
}
}
validateEnvironment();
async function runAutonomousMode(interval = 10) {
console.log("Starting autonomous mode...");
const openai = createOpenAI({
apiKey: process.env.OPENAI_API_KEY as string,
});
console.log("Starting autonomous mode...");
const openai = createOpenAI({
apiKey: process.env.OPENAI_API_KEY as string,
});
const solanaAgent = new SolanaAgentKit(
process.env.SOLANA_PRIVATE_KEY!,
process.env.RPC_URL!,
{
OPENAI_API_KEY: process.env.OPENAI_API_KEY!,
},
);
const solanaAgent = new SolanaAgentKit(
process.env.SOLANA_PRIVATE_KEY!,
process.env.RPC_URL!,
{
OPENAI_API_KEY: process.env.OPENAI_API_KEY!,
},
);
const tools = createVercelAITools(solanaAgent);
const tools = createVercelAITools(solanaAgent);
while (true) {
try {
const thought =
"Be creative and do something interesting on the blockchain. " +
"Choose an action or set of actions and execute it that highlights your abilities.";
while (true) {
try {
const thought =
"Be creative and do something interesting on the blockchain. " +
"Choose an action or set of actions and execute it that highlights your abilities.";
const response = streamText({
prompt: thought,
tools,
model: openai("gpt-4o-mini"),
temperature: 0.7,
system: `You are a helpful agent that can interact onchain using the Solana Agent Kit. You are
const response = streamText({
prompt: thought,
tools,
model: openai("gpt-4o-mini"),
temperature: 0.7,
system: `You are a helpful agent that can interact onchain using the Solana Agent Kit. You are
empowered to interact onchain using your tools. If you ever need funds, you can request them from the
faucet. If not, you can provide your wallet details and request funds from the user. If there is a 5XX
(internal) HTTP error code, ask the user to try again later. If someone asks you to do something you
can't do with your currently available tools, you must say so, and encourage them to implement it
themselves using the Solana Agent Kit, recommend they go to https://www.solanaagentkit.xyz for more information. Be
concise and helpful with your responses. Refrain from restating your tools' descriptions unless it is explicitly requested.`,
maxSteps: 10,
});
maxSteps: 10,
});
for await (const textPart of response.textStream) {
process.stdout.write(textPart);
}
console.log();
for await (const textPart of response.textStream) {
process.stdout.write(textPart);
}
console.log();
await new Promise((resolve) => setTimeout(resolve, interval * 1000));
} catch (error) {
if (error instanceof Error) {
console.error("Error:", error.message);
}
process.exit(1);
}
}
await new Promise((resolve) => setTimeout(resolve, interval * 1000));
} catch (error) {
if (error instanceof Error) {
console.error("Error:", error.message);
}
process.exit(1);
}
}
}
async function runChatMode() {
console.log("Starting chat mode... Type 'exit' to end.");
const openai = createOpenAI({
apiKey: process.env.OPENAI_API_KEY as string,
});
console.log("Starting chat mode... Type 'exit' to end.");
const openai = createOpenAI({
apiKey: process.env.OPENAI_API_KEY as string,
});
const solanaAgent = new SolanaAgentKit(
process.env.SOLANA_PRIVATE_KEY!,
process.env.RPC_URL!,
{
OPENAI_API_KEY: process.env.OPENAI_API_KEY!,
},
);
const solanaAgent = new SolanaAgentKit(
process.env.SOLANA_PRIVATE_KEY!,
process.env.RPC_URL!,
{
OPENAI_API_KEY: process.env.OPENAI_API_KEY!,
},
);
const tools = createVercelAITools(solanaAgent);
console.log(tools);
const tools = createVercelAITools(solanaAgent);
console.log(tools);
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
const question = (prompt: string): Promise<string> =>
new Promise((resolve) => rl.question(prompt, resolve));
const question = (prompt: string): Promise<string> =>
new Promise((resolve) => rl.question(prompt, resolve));
try {
while (true) {
const userInput = await question("\nPrompt: ");
try {
while (true) {
const userInput = await question("\nPrompt: ");
if (userInput.toLowerCase() === "exit") {
break;
}
if (userInput.toLowerCase() === "exit") {
break;
}
const response = streamText({
prompt: userInput,
tools,
model: openai("gpt-4o-mini"),
temperature: 0.7,
system: `You are a helpful agent that can interact onchain using the Solana Agent Kit. You are
const response = streamText({
prompt: userInput,
tools,
model: openai("gpt-4o-mini"),
temperature: 0.7,
system: `You are a helpful agent that can interact onchain using the Solana Agent Kit. You are
empowered to interact onchain using your tools. If you ever need funds, you can request them from the
faucet. If not, you can provide your wallet details and request funds from the user. If there is a 5XX
(internal) HTTP error code, ask the user to try again later. If someone asks you to do something you
can't do with your currently available tools, you must say so, and encourage them to implement it
themselves using the Solana Agent Kit, recommend they go to https://www.solanaagentkit.xyz for more information. Be
concise and helpful with your responses. Refrain from restating your tools' descriptions unless it is explicitly requested.`,
maxSteps: 10,
});
maxSteps: 10,
});
for await (const textPart of response.textStream) {
process.stdout.write(textPart);
}
console.log();
}
} catch (error) {
if (error instanceof Error) {
console.error("Error:", error.message);
}
process.exit(1);
} finally {
rl.close();
}
for await (const textPart of response.textStream) {
process.stdout.write(textPart);
}
console.log();
}
} catch (error) {
if (error instanceof Error) {
console.error("Error:", error.message);
}
process.exit(1);
} finally {
rl.close();
}
}
async function chooseMode(): Promise<"chat" | "auto"> {
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
const question = (prompt: string): Promise<string> =>
new Promise((resolve) => rl.question(prompt, resolve));
const question = (prompt: string): Promise<string> =>
new Promise((resolve) => rl.question(prompt, resolve));
while (true) {
console.log("\nAvailable modes:");
console.log("1. chat - Interactive chat mode");
console.log("2. auto - Autonomous action mode");
while (true) {
console.log("\nAvailable modes:");
console.log("1. chat - Interactive chat mode");
console.log("2. auto - Autonomous action mode");
const choice = (await question("\nChoose a mode (enter number or name): "))
.toLowerCase()
.trim();
const choice = (await question("\nChoose a mode (enter number or name): "))
.toLowerCase()
.trim();
rl.close();
rl.close();
if (choice === "1" || choice === "chat") {
return "chat";
} else if (choice === "2" || choice === "auto") {
return "auto";
}
console.log("Invalid choice. Please try again.");
}
if (choice === "1" || choice === "chat") {
return "chat";
} else if (choice === "2" || choice === "auto") {
return "auto";
}
console.log("Invalid choice. Please try again.");
}
}
async function main() {
try {
console.log("Starting Agent...");
const mode = await chooseMode();
try {
console.log("Starting Agent...");
const mode = await chooseMode();
if (mode === "chat") {
await runChatMode();
} else {
await runAutonomousMode();
}
} catch (error) {
if (error instanceof Error) {
console.error("Error:", error.message);
}
process.exit(1);
}
if (mode === "chat") {
await runChatMode();
} else {
await runAutonomousMode();
}
} catch (error) {
if (error instanceof Error) {
console.error("Error:", error.message);
}
process.exit(1);
}
}
if (require.main === module) {
main().catch((error) => {
console.error("Fatal error:", error);
process.exit(1);
});
main().catch((error) => {
console.error("Fatal error:", error);
process.exit(1);
});
}

View File

@@ -1,4 +1,4 @@
import { SolanaAgentKit , ACTIONS} from "../src";
import { SolanaAgentKit, ACTIONS } from "../src";
import { createSolanaTools } from "../src/langchain";
import { HumanMessage } from "@langchain/core/messages";
import { MemorySaver } from "@langchain/langgraph";