From 2d25b51caed1a1af42bff4662c9f803295bbf0ac Mon Sep 17 00:00:00 2001 From: aryan Date: Sun, 8 Dec 2024 03:15:44 +0530 Subject: [PATCH] fix: test --- test/index.ts | 239 +++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 205 insertions(+), 34 deletions(-) diff --git a/test/index.ts b/test/index.ts index d86324d..c1d76de 100644 --- a/test/index.ts +++ b/test/index.ts @@ -1,42 +1,213 @@ -// import { SolanaAgentKit } from "../src"; -// import { createSolanaTools } from "../src/langchain"; -// import { OpenAI } from "@langchain/openai"; -// import { AgentExecutor } from "langchain/agents"; -// import { PromptTemplate } from "@langchain/core/prompts"; -// import { pull } from "langchain/hub"; -// import { createReactAgent } from "langchain/agents"; +import { SolanaAgentKit } from "../src"; +import { createSolanaTools } from "../src/langchain"; +import { HumanMessage } from "@langchain/core/messages"; +import { MemorySaver } from "@langchain/langgraph"; +import { createReactAgent } from "@langchain/langgraph/prebuilt"; +import { ChatOpenAI } from "@langchain/openai"; +import * as dotenv from "dotenv"; +import * as fs from "fs"; +import * as readline from "readline"; -// // Initialize SolanaAgentKit -// const solanaKit = new SolanaAgentKit(undefined, "rpc-url"); +dotenv.config(); -// // Create Solana-specific tools -// const tools = createSolanaTools(solanaKit); +function validateEnvironment(): void { + const missingVars: string[] = []; + const requiredVars = ["OPENAI_API_KEY", "HELIUS_API_KEY", "SOLANA_PRIVATE_KEY"]; + + requiredVars.forEach(varName => { + if (!process.env[varName]) { + missingVars.push(varName); + } + }); -// (async () => { -// // Define a Prompt Template for the Agent -// const prompt = await pull("hwchase17/react"); + 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); + } +} -// // Create an LLM Chain -// const llm = new OpenAI({ -// modelName: "gpt-4o-mini", -// temperature: 0, -// }); +validateEnvironment(); -// const agent = await createReactAgent({ -// llm, -// tools, -// prompt, -// }); +const WALLET_DATA_FILE = "wallet_data.txt"; -// const agentExecutor = new AgentExecutor({ -// agent, -// tools, -// maxIterations: 50, -// }); +async function initializeAgent() { + try { + const llm = new ChatOpenAI({ + modelName: "gpt-4o-mini", + temperature: 0.7, + }); -// const result = await agentExecutor.invoke({ -// input: "Deploy a token with 6 decimals ", -// }); + let walletDataStr: string | null = null; -// console.log(result); -// })(); + if (fs.existsSync(WALLET_DATA_FILE)) { + try { + walletDataStr = fs.readFileSync(WALLET_DATA_FILE, "utf8"); + } catch (error) { + console.error("Error reading wallet data:", error); + } + } + + const solanaKit = new SolanaAgentKit( + process.env.SOLANA_PRIVATE_KEY!, + `https://mainnet.helius-rpc.com/?api-key=${process.env.HELIUS_API_KEY}`, + process.env.OPENAI_API_KEY! + ); + + const tools = createSolanaTools(solanaKit); + const memory = new MemorySaver(); + const config = { configurable: { thread_id: "Solana Agent Kit!" } }; + + const agent = createReactAgent({ + 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 + (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://sendai.fun/kit for more information. Be + concise and helpful with your responses. Refrain from restating your tools' descriptions unless it is + explicitly requested. + `, + }); + + if (walletDataStr) { + fs.writeFileSync(WALLET_DATA_FILE, walletDataStr); + } + + return { agent, config }; + } catch (error) { + console.error("Failed to initialize agent:", error); + throw error; + } +} + +async function runAutonomousMode(agent: any, config: any, interval = 10) { + console.log("Starting autonomous mode..."); + + 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 stream = await agent.stream({ messages: [new HumanMessage(thought)] }, config); + + for await (const chunk of stream) { + if ("agent" in chunk) { + console.log(chunk.agent.messages[0].content); + } else if ("tools" in chunk) { + console.log(chunk.tools.messages[0].content); + } + console.log("-------------------"); + } + + 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(agent: any, config: any) { + console.log("Starting chat mode... Type 'exit' to end."); + + const rl = readline.createInterface({ + input: process.stdin, + output: process.stdout, + }); + + const question = (prompt: string): Promise => + new Promise(resolve => rl.question(prompt, resolve)); + + try { + while (true) { + const userInput = await question("\nPrompt: "); + + if (userInput.toLowerCase() === "exit") { + break; + } + + const stream = await agent.stream({ messages: [new HumanMessage(userInput)] }, config); + + for await (const chunk of stream) { + if ("agent" in chunk) { + console.log(chunk.agent.messages[0].content); + } else if ("tools" in chunk) { + console.log(chunk.tools.messages[0].content); + } + 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 question = (prompt: string): Promise => + 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"); + + const choice = (await question("\nChoose a mode (enter number or name): ")) + .toLowerCase() + .trim(); + + rl.close(); + + 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 { agent, config } = await initializeAgent(); + const mode = await chooseMode(); + + if (mode === "chat") { + await runChatMode(agent, config); + } else { + await runAutonomousMode(agent, config); + } + } 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); + }); +}