From 17456a0af77c30a5823579d0ed29dcfaead31fc2 Mon Sep 17 00:00:00 2001 From: CarsonRoscoe Date: Mon, 10 Mar 2025 19:24:54 -0400 Subject: [PATCH 01/11] feat: initial commit --- typescript/create-onchain-agent/src/cli.ts | 87 +++++-- .../create-onchain-agent/src/constants.ts | 92 +++++--- .../create-onchain-agent/src/fileSystem.ts | 12 +- typescript/create-onchain-agent/src/types.ts | 8 +- typescript/create-onchain-agent/src/utils.ts | 61 +++-- .../custom-evm/viem/prepare-agentkit.ts | 132 +++++++++++ .../agentkit/evm/cdp/prepare-agentkit.ts | 112 +++++++++ .../agentkit/evm/privy/prepare-agentkit.ts | 121 ++++++++++ .../evm/smart/prepare-agentkit.ts} | 102 +------- .../agentkit/evm/viem/prepare-agentkit.ts | 119 ++++++++++ .../agentkit/svm/privy/prepare-agentkit.ts | 112 +++++++++ .../svm/solanaKeypair/prepare-agentkit.ts | 118 ++++++++++ .../app/api/agent/custom-evm/viem/route.ts | 220 ------------------ .../next/app/api/agent/evm/cdp/route.ts | 200 ---------------- .../next/app/api/agent/evm/privy/route.ts | 209 ----------------- .../next/app/api/agent/evm/viem/route.ts | 207 ---------------- .../agent/framework/langchain/create-agent.ts | 61 +++++ .../framework/langchain/prepare-agentkit.ts | 19 ++ .../api/agent/framework/langchain/route.ts | 51 ++++ .../framework/vercel-ai-sdk/create-agent.ts | 63 +++++ .../vercel-ai-sdk/prepare-agentkit.ts | 19 ++ .../agent/framework/vercel-ai-sdk/route.ts | 51 ++++ .../next/app/api/agent/svm/privy/route.ts | 200 ---------------- .../app/api/agent/svm/solanaKeypair/route.ts | 206 ---------------- .../templates/next/package.json | 5 +- 25 files changed, 1155 insertions(+), 1432 deletions(-) create mode 100644 typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/custom-evm/viem/prepare-agentkit.ts create mode 100644 typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/evm/cdp/prepare-agentkit.ts create mode 100644 typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/evm/privy/prepare-agentkit.ts rename typescript/create-onchain-agent/templates/next/app/api/agent/{evm/smart/route.ts => agentkit/evm/smart/prepare-agentkit.ts} (51%) create mode 100644 typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/evm/viem/prepare-agentkit.ts create mode 100644 typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/svm/privy/prepare-agentkit.ts create mode 100644 typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/svm/solanaKeypair/prepare-agentkit.ts delete mode 100644 typescript/create-onchain-agent/templates/next/app/api/agent/custom-evm/viem/route.ts delete mode 100644 typescript/create-onchain-agent/templates/next/app/api/agent/evm/cdp/route.ts delete mode 100644 typescript/create-onchain-agent/templates/next/app/api/agent/evm/privy/route.ts delete mode 100644 typescript/create-onchain-agent/templates/next/app/api/agent/evm/viem/route.ts create mode 100644 typescript/create-onchain-agent/templates/next/app/api/agent/framework/langchain/create-agent.ts create mode 100644 typescript/create-onchain-agent/templates/next/app/api/agent/framework/langchain/prepare-agentkit.ts create mode 100644 typescript/create-onchain-agent/templates/next/app/api/agent/framework/langchain/route.ts create mode 100644 typescript/create-onchain-agent/templates/next/app/api/agent/framework/vercel-ai-sdk/create-agent.ts create mode 100644 typescript/create-onchain-agent/templates/next/app/api/agent/framework/vercel-ai-sdk/prepare-agentkit.ts create mode 100644 typescript/create-onchain-agent/templates/next/app/api/agent/framework/vercel-ai-sdk/route.ts delete mode 100644 typescript/create-onchain-agent/templates/next/app/api/agent/svm/privy/route.ts delete mode 100644 typescript/create-onchain-agent/templates/next/app/api/agent/svm/solanaKeypair/route.ts diff --git a/typescript/create-onchain-agent/src/cli.ts b/typescript/create-onchain-agent/src/cli.ts index 93239914b..86f6a2706 100644 --- a/typescript/create-onchain-agent/src/cli.ts +++ b/typescript/create-onchain-agent/src/cli.ts @@ -5,14 +5,15 @@ import path from "path"; import pc from "picocolors"; import prompts from "prompts"; import { EVM_NETWORKS, NetworkToWalletProviders, SVM_NETWORKS } from "./constants.js"; -import { Network, WalletProviderChoice } from "./types.js"; +import { Network, WalletProviderChoice, Framework, Template } from "./types.js"; import { copyTemplate } from "./fileSystem.js"; import { - handleSelection, + handleNextSelection, isValidPackageName, toValidPackageName, getWalletProviders, } from "./utils.js"; +import { Frameworks, FrameworkToTemplates } from "./constants.js"; /** * Initializes the project creation process. @@ -47,6 +48,8 @@ async function init() { | "chainId" | "rpcUrl" | "walletProvider" + | "framework" + | "template" >; try { @@ -76,6 +79,26 @@ async function init() { initial: (_, { projectName }: { projectName: string }) => toValidPackageName(projectName), validate: dir => isValidPackageName(dir) || "Invalid package.json name", }, + { + type: "select", + name: "framework", + message: pc.reset("Choose a framework:"), + choices: Frameworks.map(framework => ({ + title: framework, + value: framework, + })), + }, + { + type: (prev, { framework }) => + FrameworkToTemplates[framework as Framework].length > 1 ? "select" : null, + name: "template", + message: pc.reset("Choose a template:"), + choices: (prev, { framework }) => + FrameworkToTemplates[framework as Framework].map(template => ({ + title: template, + value: template, + })), + }, { type: "select", name: "networkFamily", @@ -207,38 +230,54 @@ async function init() { } process.exit(1); } - const { projectName, network, chainId, rpcUrl } = result; + const { + projectName, + network, + chainId, + rpcUrl, + framework + } = result; const packageName = result.packageName || toValidPackageName(projectName); const walletProvider = result.walletProvider || "Viem"; + // If template wasn't selected (because there was only one option), use the first template + const template = result.template || FrameworkToTemplates[framework as Framework][0]; const spinner = ora(`Creating ${projectName}...`).start(); // Copy template over to new project - const root = await copyTemplate(projectName, packageName); + const root = await copyTemplate(projectName, packageName, template); // Handle selection-specific logic over copied-template - await handleSelection(root, walletProvider, network, chainId, rpcUrl); - - spinner.succeed(); - console.log(pc.blueBright(`\nSuccessfully created your AgentKit project in ${root}`)); - - console.log(`\nFrameworks:`); - console.log(pc.gray("- AgentKit")); - console.log(pc.gray("- React")); - console.log(pc.gray("- Next.js")); - console.log(pc.gray("- Tailwind CSS")); - console.log(pc.gray("- ESLint")); - - console.log(pc.bold("\nWhat's Next?")); + switch (template) { + case "next": + await handleNextSelection(root, walletProvider, network, chainId, rpcUrl, framework); - console.log(`\nTo get started, run the following commands:\n`); - if (root !== process.cwd()) { - console.log(` - cd ${path.relative(process.cwd(), root)}`); + spinner.succeed(); + console.log(pc.blueBright(`\nSuccessfully created your AgentKit project in ${root}`)); + + console.log(`\nFrameworks:`); + console.log(pc.gray("- AgentKit")); + console.log(pc.gray(`- ${framework}`)); + console.log(pc.gray("- React")); + console.log(pc.gray("- Next.js")); + console.log(pc.gray("- Tailwind CSS")); + console.log(pc.gray("- ESLint")); + + console.log(pc.bold("\nWhat's Next?")); + + console.log(`\nTo get started, run the following commands:\n`); + if (root !== process.cwd()) { + console.log(` - cd ${path.relative(process.cwd(), root)}`); + } + console.log(" - npm install"); + console.log(pc.gray(" - # Open .env.local and configure your API keys")); + console.log(" - mv .env.local .env"); + console.log(" - npm run dev"); + break; + case "mcpServer": + // TODO: Implement MCP Server template + break; } - console.log(" - npm install"); - console.log(pc.gray(" - # Open .env.local and configure your API keys")); - console.log(" - mv .env.local .env"); - console.log(" - npm run dev"); console.log(pc.bold("\nLearn more")); console.log(" - Checkout the docs"); diff --git a/typescript/create-onchain-agent/src/constants.ts b/typescript/create-onchain-agent/src/constants.ts index 06607f3b6..80bd27704 100644 --- a/typescript/create-onchain-agent/src/constants.ts +++ b/typescript/create-onchain-agent/src/constants.ts @@ -3,7 +3,9 @@ import { Network, SVMNetwork, WalletProviderChoice, - WalletProviderRouteConfiguration, + AgentkitRouteConfiguration, + Framework, + Template, } from "./types"; export const EVM_NETWORKS: EVMNetwork[] = [ @@ -56,18 +58,18 @@ export const WalletProviderChoices: WalletProviderChoice[] = [ ]), ]; -export const WalletProviderRouteConfigurations: Record< +export const AgentkitRouteConfigurations: Record< "EVM" | "CUSTOM_EVM" | "SVM", - Partial> + Partial> > = { EVM: { CDP: { env: { topComments: ["Get keys from CDP Portal: https://portal.cdp.coinbase.com/"], - required: ["CDP_API_KEY_NAME=", "CDP_API_KEY_PRIVATE_KEY="], + required: ["CDP_API_KEY_NAME", "CDP_API_KEY_PRIVATE_KEY"], optional: [], }, - apiRoute: "evm/cdp/route.ts", + prepareAgentkitRoute: "evm/cdp/prepare-agentkit.ts", }, Viem: { env: { @@ -75,10 +77,10 @@ export const WalletProviderRouteConfigurations: Record< "Export private key from your Ethereum wallet and save", "Get keys from CDP Portal: https://portal.cdp.coinbase.com/", ], - required: ["PRIVATE_KEY="], - optional: ["CDP_API_KEY_NAME=", "CDP_API_KEY_PRIVATE_KEY="], + required: ["PRIVATE_KEY"], + optional: ["CDP_API_KEY_NAME", "CDP_API_KEY_PRIVATE_KEY"], }, - apiRoute: "evm/viem/route.ts", + prepareAgentkitRoute: "evm/viem/prepare-agentkit.ts", }, Privy: { env: { @@ -86,17 +88,17 @@ export const WalletProviderRouteConfigurations: Record< "Get keys from Privy Dashboard: https://dashboard.privy.io/", "Get keys from CDP Portal: https://portal.cdp.coinbase.com/", ], - required: ["PRIVY_APP_ID=", "PRIVY_APP_SECRET="], + required: ["PRIVY_APP_ID", "PRIVY_APP_SECRET"], optional: [ - "CHAIN_ID=", - "PRIVY_WALLET_ID=", - "PRIVY_WALLET_AUTHORIZATION_PRIVATE_KEY=", - "PRIVY_WALLET_AUTHORIZATION_KEY_ID=", - "CDP_API_KEY_NAME=", - "CDP_API_KEY_PRIVATE_KEY=", + "CHAIN_ID", + "PRIVY_WALLET_ID", + "PRIVY_WALLET_AUTHORIZATION_PRIVATE_KEY", + "PRIVY_WALLET_AUTHORIZATION_KEY_ID", + "CDP_API_KEY_NAME", + "CDP_API_KEY_PRIVATE_KEY", ], }, - apiRoute: "evm/privy/route.ts", + prepareAgentkitRoute: "evm/privy/prepare-agentkit.ts", }, SmartWallet: { env: { @@ -104,10 +106,10 @@ export const WalletProviderRouteConfigurations: Record< "Get keys from CDP Portal: https://portal.cdp.coinbase.com/", "Optionally provide a private key, otherwise one will be generated", ], - required: ["CDP_API_KEY_NAME=", "CDP_API_KEY_PRIVATE_KEY="], - optional: ["PRIVATE_KEY="], + required: ["CDP_API_KEY_NAME", "CDP_API_KEY_PRIVATE_KEY"], + optional: ["PRIVATE_KEY"], }, - apiRoute: "evm/smart/route.ts", + prepareAgentkitRoute: "evm/smart/prepare-agentkit.ts", }, }, CUSTOM_EVM: { @@ -117,10 +119,10 @@ export const WalletProviderRouteConfigurations: Record< "Export private key from your Ethereum wallet and save", "Get keys from CDP Portal: https://portal.cdp.coinbase.com/", ], - required: ["PRIVATE_KEY="], - optional: ["CDP_API_KEY_NAME=", "CDP_API_KEY_PRIVATE_KEY="], + required: ["PRIVATE_KEY"], + optional: ["CDP_API_KEY_NAME", "CDP_API_KEY_PRIVATE_KEY"], }, - apiRoute: "custom-evm/viem/route.ts", + prepareAgentkitRoute: "custom-evm/viem/prepare-agentkit.ts", }, }, SVM: { @@ -130,10 +132,10 @@ export const WalletProviderRouteConfigurations: Record< "Export private key from your Solana wallet and save", "Get keys from CDP Portal: https://portal.cdp.coinbase.com/", ], - required: ["SOLANA_PRIVATE_KEY="], - optional: ["SOLANA_RPC_URL=", "CDP_API_KEY_NAME=", "CDP_API_KEY_PRIVATE_KEY="], + required: ["SOLANA_PRIVATE_KEY"], + optional: ["SOLANA_RPC_URL", "CDP_API_KEY_NAME", "CDP_API_KEY_PRIVATE_KEY"], }, - apiRoute: "svm/solanaKeypair/route.ts", + prepareAgentkitRoute: "svm/solanaKeypair/prepare-agentkit.ts", }, Privy: { env: { @@ -141,16 +143,42 @@ export const WalletProviderRouteConfigurations: Record< "Get keys from Privy Dashboard: https://dashboard.privy.io/", "Get keys from CDP Portal: https://portal.cdp.coinbase.com/", ], - required: ["PRIVY_APP_ID=", "PRIVY_APP_SECRET="], + required: ["PRIVY_APP_ID", "PRIVY_APP_SECRET"], optional: [ - "PRIVY_WALLET_ID=", - "PRIVY_WALLET_AUTHORIZATION_PRIVATE_KEY=", - "PRIVY_WALLET_AUTHORIZATION_KEY_ID=", - "CDP_API_KEY_NAME=", - "CDP_API_KEY_PRIVATE_KEY=", + "PRIVY_WALLET_ID", + "PRIVY_WALLET_AUTHORIZATION_PRIVATE_KEY", + "PRIVY_WALLET_AUTHORIZATION_KEY_ID", + "CDP_API_KEY_NAME", + "CDP_API_KEY_PRIVATE_KEY", ], }, - apiRoute: "svm/privy/route.ts", + prepareAgentkitRoute: "svm/privy/prepare-agentkit.ts", }, }, }; + +export const Frameworks: Framework[] = ["Langchain", "Vercel AI SDK", "Model Context Protocol"]; + +export const Templates: Template[] = ["next", "mcpServer"]; + +export const FrameworkToTemplates: Record = { + "Langchain": ["next"], + "Vercel AI SDK": ["next"], + "Model Context Protocol": ["mcpServer"], +}; + +export type NextTemplateRouteConfiguration = { + createAgentRoute: `${string}.ts`, + apiRoute: `${string}.ts`, +}; + +export const NextTemplateRouteConfigurations: Partial> = { + "Langchain": { + apiRoute: "langchain/route.ts", + createAgentRoute: "langchain/create-agent.ts", + }, + "Vercel AI SDK": { + apiRoute: "vercel-ai-sdk/route.ts", + createAgentRoute: "vercel-ai-sdk/create-agent.ts", + }, +}; diff --git a/typescript/create-onchain-agent/src/fileSystem.ts b/typescript/create-onchain-agent/src/fileSystem.ts index bd6302dfe..2ad87252e 100644 --- a/typescript/create-onchain-agent/src/fileSystem.ts +++ b/typescript/create-onchain-agent/src/fileSystem.ts @@ -2,8 +2,9 @@ import fs from "fs"; import path from "path"; import { fileURLToPath } from "url"; import { optimizedCopy } from "./utils.js"; +import { Template } from "./types.js"; -const sourceDir = path.resolve(fileURLToPath(import.meta.url), "../../../templates/next"); +const sourceDir = path.resolve(fileURLToPath(import.meta.url), "../../../templates"); const renameFiles: Record = { _gitignore: ".gitignore", @@ -18,8 +19,8 @@ const excludeFiles = [".DS_Store", "Thumbs.db"]; * * @returns {string} The source directory path. */ -function getSourceDir(): string { - return sourceDir; +function getSourceDir(template: Template): string { + return path.join(sourceDir, template); } /** @@ -62,11 +63,12 @@ async function copyDir(src: string, dest: string): Promise { * * @param {string} projectName - The name of the new project directory. * @param {string} packageName - The npm package name to use (auto-formatted if empty). + * @param {Template} template - The template to use. * @returns {Promise} The path of the newly created project directory. */ -export async function copyTemplate(projectName: string, packageName: string): Promise { +export async function copyTemplate(projectName: string, packageName: string, template: Template): Promise { const root = path.join(process.cwd(), projectName); - await copyDir(getSourceDir(), root); + await copyDir(getSourceDir(template), root); const pkgPath = path.join(root, "package.json"); const pkg = JSON.parse(await fs.promises.readFile(pkgPath, "utf-8")); diff --git a/typescript/create-onchain-agent/src/types.ts b/typescript/create-onchain-agent/src/types.ts index 88e586baa..ceaf95d3a 100644 --- a/typescript/create-onchain-agent/src/types.ts +++ b/typescript/create-onchain-agent/src/types.ts @@ -16,13 +16,13 @@ export type Network = EVMNetwork | SVMNetwork; export type WalletProviderChoice = "CDP" | "Viem" | "Privy" | "SolanaKeypair" | "SmartWallet"; -export type WalletProviderRouteConfiguration = { +export type AgentkitRouteConfiguration = { env: { topComments: string[]; required: string[]; optional: string[]; }; - apiRoute: string; + prepareAgentkitRoute: `${string}.ts`; }; export type NetworkSelection = { @@ -32,3 +32,7 @@ export type NetworkSelection = { chainId?: string; rpcUrl?: string; }; + +export type Framework = "Langchain" | "Vercel AI SDK" | "Model Context Protocol"; + +export type Template = 'next' | 'mcpServer'; \ No newline at end of file diff --git a/typescript/create-onchain-agent/src/utils.ts b/typescript/create-onchain-agent/src/utils.ts index 05b706632..d34635da3 100644 --- a/typescript/create-onchain-agent/src/utils.ts +++ b/typescript/create-onchain-agent/src/utils.ts @@ -1,12 +1,13 @@ import fs from "fs/promises"; import path from "path"; -import { EVMNetwork, Network, SVMNetwork, WalletProviderChoice } from "./types"; +import { EVMNetwork, Framework, Network, SVMNetwork, WalletProviderChoice } from "./types"; import { EVM_NETWORKS, NetworkToWalletProviders, NON_CDP_SUPPORTED_EVM_WALLET_PROVIDERS, SVM_NETWORKS, - WalletProviderRouteConfigurations, + AgentkitRouteConfigurations, + NextTemplateRouteConfigurations, } from "./constants.js"; /** @@ -176,6 +177,7 @@ export const getWalletProviders = (network?: Network): WalletProviderChoice[] => * - Deletes all unselected API routes and cleans up empty directories. * * @param {string} root - The root directory of the project. + * @param {Framework} framework - The selected framework. * @param {WalletProviderChoice} walletProvider - The selected wallet provider. * @param {Network} [network] - The optional blockchain network. * @param {string} [chainId] - The optional chain ID for the network. @@ -183,8 +185,9 @@ export const getWalletProviders = (network?: Network): WalletProviderChoice[] => * @throws {Error} If neither `network` nor `chainId` are provided, or if the selected combination is invalid. * @returns {Promise} A promise that resolves when the selection process is complete. */ -export async function handleSelection( +export async function handleNextSelection( root: string, + framework: Framework, walletProvider: WalletProviderChoice, network?: Network, chainId?: string, @@ -197,61 +200,57 @@ export async function handleSelection( throw new Error("Unsupported network and chainId selected"); } - const selectedRouteConfig = WalletProviderRouteConfigurations[networkFamily][walletProvider]; + const agentkitRouteConfig = AgentkitRouteConfigurations[networkFamily][walletProvider]; + const frameworkRouteConfig = NextTemplateRouteConfigurations[framework]; - if (!selectedRouteConfig) { + if (!agentkitRouteConfig) { throw new Error("Selected invalid network & wallet provider combination"); } + if (!frameworkRouteConfig) { + throw new Error("Selected invalid framework for this template"); + } + // Create .env file const envPath = path.join(root, ".env.local"); const envLines = [ // Start file with notes regarding .env var setup ...[ "Get keys from OpenAI Platform: https://platform.openai.com/api-keys", - ...selectedRouteConfig.env.topComments, + ...agentkitRouteConfig.env.topComments, ] .map(comment => `# ${comment}`) .join("\n"), // Continue with # Required section "\n\n# Required\n", - ...["OPENAI_API_KEY=", ...selectedRouteConfig.env.required].join("\n"), + ...["OPENAI_API_KEY=", ...agentkitRouteConfig.env.required.map(line => `${line}=`)].join("\n"), // Finish with # Optional section "\n\n# Optional\n", ...[ `NETWORK_ID=${network ?? ""}`, rpcUrl ? `RPC_URL=${rpcUrl}` : null, chainId ? `CHAIN_ID=${chainId}` : null, - ...selectedRouteConfig.env.optional, + ...agentkitRouteConfig.env.optional.map(line => `${line}=`), ] .filter(Boolean) .join("\n"), ]; await fs.writeFile(envPath, envLines); - // Promote selected route (move `apiRoute` to `api/agent/route.ts`) - const selectedRoutePath = path.join(agentDir, selectedRouteConfig.apiRoute); - const newRoutePath = path.join(agentDir, "route.ts"); - - await fs.rename(selectedRoutePath, newRoutePath); + // Promose selected routes to + const promoteRoute = async (toPromose: string, type: string, to: string) => { + const selectedRoutePath = path.join(agentDir, type, toPromose); + const newRoutePath = path.join(agentDir, to); + await fs.rename(selectedRoutePath, newRoutePath); + } - // Delete all unselected routes - const allRouteConfigurations = Object.values(WalletProviderRouteConfigurations) - .flatMap(routeConfigurations => Object.values(routeConfigurations)) - .filter(x => x); - const providerRoutes = allRouteConfigurations.map(config => path.join(agentDir, config.apiRoute)); - for (const routePath of providerRoutes) { - // Remove file - await fs.rm(routePath, { recursive: true, force: true }); + await promoteRoute(agentkitRouteConfig.prepareAgentkitRoute, 'agentkit', "prepare-agentkit.ts"); + await promoteRoute(frameworkRouteConfig.createAgentRoute, 'framework', "create-agent.ts"); + await promoteRoute(frameworkRouteConfig.apiRoute, 'framework', "route.ts"); - // If directory is empty, remove directory - const parentFolder = path.dirname(routePath); - const files = await fs.readdir(parentFolder); - if (files.length === 0) { - await fs.rm(parentFolder, { recursive: true, force: true }); - } - } - await fs.rm(path.join(agentDir, "evm"), { recursive: true, force: true }); - await fs.rm(path.join(agentDir, "svm"), { recursive: true, force: true }); - await fs.rm(path.join(agentDir, "custom-evm"), { recursive: true, force: true }); + // Delete boilerplate routes + await fs.rm(path.join(agentDir, 'agentkit'), { recursive: true, force: true }); + await fs.rm(path.join(agentDir, 'framework'), { recursive: true, force: true }); } + + diff --git a/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/custom-evm/viem/prepare-agentkit.ts b/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/custom-evm/viem/prepare-agentkit.ts new file mode 100644 index 000000000..08c5e5159 --- /dev/null +++ b/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/custom-evm/viem/prepare-agentkit.ts @@ -0,0 +1,132 @@ +import { + ActionProvider, + AgentKit, + cdpApiActionProvider, + erc20ActionProvider, + pythActionProvider, + ViemWalletProvider, + walletActionProvider, + WalletProvider, + wethActionProvider, +} from "@coinbase/agentkit"; +import fs from "fs"; +import { createWalletClient, http } from "viem"; +import { generatePrivateKey, privateKeyToAccount } from "viem/accounts"; + +/** + * AgentKit Integration Route + * + * This file is your gateway to integrating AgentKit with your product. + * It defines the interaction between your system and the AI agent, + * allowing you to configure the agent to suit your needs. + * + * # Key Steps to Customize Your Agent:** + * + * 1. Select your LLM: + * - Modify the `ChatOpenAI` instantiation to choose your preferred LLM. + * + * 2. Set up your WalletProvider: + * - Learn more: https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#evm-wallet-providers + * + * 3️. Set up your ActionProviders: + * - ActionProviders define what your agent can do. + * - Choose from built-in providers or create your own: + * - Built-in: https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#action-providers + * - Custom: https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#creating-an-action-provider + * + * 4. Instantiate your Agent: + * - Pass the LLM, tools, and memory into `createReactAgent()` to bring your agent to life. + * + * # Next Steps: + * - Explore the AgentKit README: https://github.com/coinbase/agentkit + * - Learn more about available WalletProviders & ActionProviders. + * - Experiment with custom ActionProviders for your unique use case. + * + * ## Want to contribute? + * Join us in shaping AgentKit! Check out the contribution guide: + * - https://github.com/coinbase/agentkit/blob/main/CONTRIBUTING.md + * - https://discord.gg/CDP + */ + +// Configure a file to persist a user's private key if none provided +const WALLET_DATA_FILE = "wallet_data.txt"; + +/** +* Prepares the AgentKit and WalletProvider. +* +* @function prepareAgentkitAndWalletProvider +* @returns {Promise<{ agentkit: AgentKit, walletProvider: WalletProvider }>} The initialized AI agent. +* +* @description Handles agent setup +* +* @throws {Error} If the agent initialization fails. +*/ +export async function prepareAgentkitAndWalletProvider(): Promise<{ agentkit: AgentKit, walletProvider: WalletProvider }> { + try { + // Initialize WalletProvider: https://docs.cdp.coinbase.com/agentkit/docs/wallet-management + let privateKey = process.env.PRIVATE_KEY as `0x${string}`; + if (!privateKey) { + if (fs.existsSync(WALLET_DATA_FILE)) { + privateKey = JSON.parse(fs.readFileSync(WALLET_DATA_FILE, "utf8")).privateKey; + console.info("Found private key in wallet_data.txt"); + } else { + privateKey = generatePrivateKey(); + fs.writeFileSync(WALLET_DATA_FILE, JSON.stringify({ privateKey })); + console.log("Created new private key and saved to wallet_data.txt"); + console.log( + "We recommend you save this private key to your .env file and delete wallet_data.txt afterwards.", + ); + } + } + const account = privateKeyToAccount(privateKey); + + const rpcUrl = process.env.RPC_URL as string; + const chainId = process.env.CHAIN_ID as string; + const client = createWalletClient({ + account, + // Customize the chain metadata to match your custom chain + chain: { + id: parseInt(chainId), + rpcUrls: { + default: { + http: [rpcUrl], + }, + }, + name: "Custom Chain", + nativeCurrency: { + name: "Ether", + symbol: "ETH", + decimals: 18, + }, + }, + transport: http(), + }); + const walletProvider = new ViemWalletProvider(client); + + // Initialize AgentKit: https://docs.cdp.coinbase.com/agentkit/docs/agent-actions + const actionProviders: ActionProvider[] = [ + wethActionProvider(), + pythActionProvider(), + walletActionProvider(), + erc20ActionProvider(), + ]; + const canUseCdpApi = process.env.CDP_API_KEY_NAME && process.env.CDP_API_KEY_PRIVATE_KEY; + if (canUseCdpApi) { + actionProviders.push( + cdpApiActionProvider({ + apiKeyName: process.env.CDP_API_KEY_NAME, + apiKeyPrivateKey: process.env.CDP_API_KEY_PRIVATE_KEY, + }), + ); + } + const agentkit = await AgentKit.from({ + walletProvider, + actionProviders, + }); + + return { agentkit, walletProvider }; + } catch (error) { + console.error("Error initializing agent:", error); + throw new Error("Failed to initialize agent"); + } +} diff --git a/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/evm/cdp/prepare-agentkit.ts b/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/evm/cdp/prepare-agentkit.ts new file mode 100644 index 000000000..5a2caf3aa --- /dev/null +++ b/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/evm/cdp/prepare-agentkit.ts @@ -0,0 +1,112 @@ +import { + AgentKit, + cdpApiActionProvider, + cdpWalletActionProvider, + CdpWalletProvider, + erc20ActionProvider, + pythActionProvider, + walletActionProvider, + WalletProvider, + wethActionProvider, +} from "@coinbase/agentkit"; +import * as fs from "fs"; + +/** +* AgentKit Integration Route +* +* This file is your gateway to integrating AgentKit with your product. +* It defines the interaction between your system and the AI agent, +* allowing you to configure the agent to suit your needs. +* +* # Key Steps to Customize Your Agent:** +* +* 1. Select your LLM: +* - Modify the `ChatOpenAI` instantiation to choose your preferred LLM. +* +* 2. Set up your WalletProvider: +* - Learn more: https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#evm-wallet-providers +* +* 3️. Set up your ActionProviders: +* - ActionProviders define what your agent can do. +* - Choose from built-in providers or create your own: +* - Built-in: https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#action-providers +* - Custom: https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#creating-an-action-provider +* +* 4. Instantiate your Agent: +* - Pass the LLM, tools, and memory into `createReactAgent()` to bring your agent to life. +* +* # Next Steps: +* - Explore the AgentKit README: https://github.com/coinbase/agentkit +* - Learn more about available WalletProviders & ActionProviders. +* - Experiment with custom ActionProviders for your unique use case. +* +* ## Want to contribute? +* Join us in shaping AgentKit! Check out the contribution guide: +* - https://github.com/coinbase/agentkit/blob/main/CONTRIBUTING.md +* - https://discord.gg/CDP +*/ + +// Configure a file to persist the agent's CDP MPC Wallet Data +const WALLET_DATA_FILE = "wallet_data.txt"; + +/** +* Prepares the AgentKit and WalletProvider. +* +* @function prepareAgentkitAndWalletProvider +* @returns {Promise<{ agentkit: AgentKit, walletProvider: WalletProvider }>} The initialized AI agent. +* +* @description Handles agent setup +* +* @throws {Error} If the agent initialization fails. +*/ +export async function prepareAgentkitAndWalletProvider(): Promise<{ agentkit: AgentKit, walletProvider: WalletProvider }> { + try { + let walletDataStr: string | null = null; + + // Read existing wallet data if available + if (fs.existsSync(WALLET_DATA_FILE)) { + try { + walletDataStr = fs.readFileSync(WALLET_DATA_FILE, "utf8"); + } catch (error) { + console.error("Error reading wallet data:", error); + // Continue without wallet data + } + } + + // Initialize WalletProvider: https://docs.cdp.coinbase.com/agentkit/docs/wallet-management + const walletProvider = await CdpWalletProvider.configureWithWallet({ + apiKeyName: process.env.CDP_API_KEY_NAME, + apiKeyPrivateKey: process.env.CDP_API_KEY_PRIVATE_KEY, + networkId: process.env.NETWORK_ID || "base-sepolia", + cdpWalletData: walletDataStr || undefined, + }); + + // Initialize AgentKit: https://docs.cdp.coinbase.com/agentkit/docs/agent-actions + const agentkit = await AgentKit.from({ + walletProvider, + actionProviders: [ + wethActionProvider(), + pythActionProvider(), + walletActionProvider(), + erc20ActionProvider(), + cdpApiActionProvider({ + apiKeyName: process.env.CDP_API_KEY_NAME, + apiKeyPrivateKey: process.env.CDP_API_KEY_PRIVATE_KEY, + }), + cdpWalletActionProvider({ + apiKeyName: process.env.CDP_API_KEY_NAME, + apiKeyPrivateKey: process.env.CDP_API_KEY_PRIVATE_KEY, + }), + ], + }); + + // Save wallet data + const exportedWallet = await walletProvider.exportWallet(); + fs.writeFileSync(WALLET_DATA_FILE, JSON.stringify(exportedWallet)); + + return { agentkit, walletProvider }; + } catch (error) { + console.error("Error initializing agent:", error); + throw new Error("Failed to initialize agent"); + } +} diff --git a/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/evm/privy/prepare-agentkit.ts b/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/evm/privy/prepare-agentkit.ts new file mode 100644 index 000000000..2120b1f70 --- /dev/null +++ b/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/evm/privy/prepare-agentkit.ts @@ -0,0 +1,121 @@ +import { + ActionProvider, + AgentKit, + cdpApiActionProvider, + erc20ActionProvider, + PrivyWalletConfig, + PrivyWalletProvider, + pythActionProvider, + walletActionProvider, + WalletProvider, + wethActionProvider, +} from "@coinbase/agentkit"; +import fs from "fs"; + +/** + * AgentKit Integration Route + * + * This file is your gateway to integrating AgentKit with your product. + * It defines the interaction between your system and the AI agent, + * allowing you to configure the agent to suit your needs. + * + * # Key Steps to Customize Your Agent:** + * + * 1. Select your LLM: + * - Modify the `ChatOpenAI` instantiation to choose your preferred LLM. + * + * 2. Set up your WalletProvider: + * - Learn more: https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#evm-wallet-providers + * + * 3️. Set up your ActionProviders: + * - ActionProviders define what your agent can do. + * - Choose from built-in providers or create your own: + * - Built-in: https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#action-providers + * - Custom: https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#creating-an-action-provider + * + * 4. Instantiate your Agent: + * - Pass the LLM, tools, and memory into `createReactAgent()` to bring your agent to life. + * + * # Next Steps: + * - Explore the AgentKit README: https://github.com/coinbase/agentkit + * - Learn more about available WalletProviders & ActionProviders. + * - Experiment with custom ActionProviders for your unique use case. + * + * ## Want to contribute? + * Join us in shaping AgentKit! Check out the contribution guide: + * - https://github.com/coinbase/agentkit/blob/main/CONTRIBUTING.md + * - https://discord.gg/CDP + */ + +// Configure a file to persist the agent's Privy Wallet Data +const WALLET_DATA_FILE = "wallet_data.txt"; + +/** + * Prepares the AgentKit and WalletProvider. + * + * @function prepareAgentkitAndWalletProvider + * @returns {Promise<{ agentkit: AgentKit, walletProvider: WalletProvider }>} The initialized AI agent. + * + * @description Handles agent setup + * + * @throws {Error} If the agent initialization fails. + */ +export async function prepareAgentkitAndWalletProvider(): Promise<{ agentkit: AgentKit, walletProvider: WalletProvider }> { + try { + // Initialize WalletProvider: https://docs.cdp.coinbase.com/agentkit/docs/wallet-management + const config: PrivyWalletConfig = { + appId: process.env.PRIVY_APP_ID as string, + appSecret: process.env.PRIVY_APP_SECRET as string, + walletId: process.env.PRIVY_WALLET_ID as string, + chainId: process.env.CHAIN_ID, + authorizationPrivateKey: process.env.PRIVY_WALLET_AUTHORIZATION_PRIVATE_KEY, + authorizationKeyId: process.env.PRIVY_WALLET_AUTHORIZATION_KEY_ID, + }; + // Try to load saved wallet data + if (fs.existsSync(WALLET_DATA_FILE)) { + const savedWallet = JSON.parse(fs.readFileSync(WALLET_DATA_FILE, "utf8")); + config.walletId = savedWallet.walletId; + config.authorizationPrivateKey = savedWallet.authorizationPrivateKey; + + if (savedWallet.chainId) { + console.log("Found chainId in wallet_data.txt:", savedWallet.chainId); + config.chainId = savedWallet.chainId; + } + } + if (!config.chainId) { + console.log("Warning: CHAIN_ID not set, defaulting to 84532 (base-sepolia)"); + config.chainId = "84532"; + } + const walletProvider = await PrivyWalletProvider.configureWithWallet(config); + + // Initialize AgentKit: https://docs.cdp.coinbase.com/agentkit/docs/agent-actions + const actionProviders: ActionProvider[] = [ + wethActionProvider(), + pythActionProvider(), + walletActionProvider(), + erc20ActionProvider(), + ]; + const canUseCdpApi = process.env.CDP_API_KEY_NAME && process.env.CDP_API_KEY_PRIVATE_KEY; + if (canUseCdpApi) { + actionProviders.push( + cdpApiActionProvider({ + apiKeyName: process.env.CDP_API_KEY_NAME, + apiKeyPrivateKey: process.env.CDP_API_KEY_PRIVATE_KEY, + }), + ); + } + const agentkit = await AgentKit.from({ + walletProvider, + actionProviders, + }); + + // Save wallet data + const exportedWallet = walletProvider.exportWallet(); + fs.writeFileSync(WALLET_DATA_FILE, JSON.stringify(exportedWallet)); + + return { agentkit, walletProvider }; + } catch (error) { + console.error("Error initializing agent:", error); + throw new Error("Failed to initialize agent"); + } +} diff --git a/typescript/create-onchain-agent/templates/next/app/api/agent/evm/smart/route.ts b/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/evm/smart/prepare-agentkit.ts similarity index 51% rename from typescript/create-onchain-agent/templates/next/app/api/agent/evm/smart/route.ts rename to typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/evm/smart/prepare-agentkit.ts index 9aade92e4..3579b23c5 100644 --- a/typescript/create-onchain-agent/templates/next/app/api/agent/evm/smart/route.ts +++ b/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/evm/smart/prepare-agentkit.ts @@ -1,19 +1,14 @@ -import { NextResponse } from "next/server"; import { AgentKit, cdpApiActionProvider, cdpWalletActionProvider, - SmartWalletProvider, erc20ActionProvider, pythActionProvider, + SmartWalletProvider, walletActionProvider, + WalletProvider, wethActionProvider, } from "@coinbase/agentkit"; -import { getLangChainTools } from "@coinbase/agentkit-langchain"; -import { ChatOpenAI } from "@langchain/openai"; -import { MemorySaver } from "@langchain/langgraph"; -import { createReactAgent } from "@langchain/langgraph/prebuilt"; -import { AgentRequest, AgentResponse } from "@/app/types/api"; import * as fs from "fs"; import { Address, Hex } from "viem"; import { generatePrivateKey, privateKeyToAccount } from "viem/accounts"; @@ -53,9 +48,6 @@ import { generatePrivateKey, privateKeyToAccount } from "viem/accounts"; * - https://discord.gg/CDP */ -// The agent -let agent: ReturnType; - // Configure a file to persist the agent's Smart Wallet + Private Key data const WALLET_DATA_FILE = "wallet_data.txt"; @@ -65,26 +57,17 @@ type WalletData = { }; /** - * Initializes and returns an instance of the AI agent. - * If an agent instance already exists, it returns the existing one. + * Prepares the AgentKit and WalletProvider. * - * @function getOrInitializeAgent - * @returns {Promise>} The initialized AI agent. + * @function prepareAgentkitAndWalletProvider + * @returns {Promise<{ agentkit: AgentKit, walletProvider: WalletProvider }>} The initialized AI agent. * * @description Handles agent setup * * @throws {Error} If the agent initialization fails. */ -async function getOrInitializeAgent(): Promise> { - // If agent has already been initialized, return it - if (agent) { - return agent; - } - +export async function prepareAgentkitAndWalletProvider(): Promise<{ agentkit: AgentKit, walletProvider: WalletProvider }> { try { - // Initialize LLM: https://platform.openai.com/docs/models#gpt-4o - const llm = new ChatOpenAI({ model: "gpt-4o-mini" }); - let walletData: WalletData | null = null; let privateKey: Hex | null = null; @@ -136,28 +119,6 @@ async function getOrInitializeAgent(): Promise Promise }} req - The incoming request object containing the user message. - * @returns {Promise>} JSON response containing the AI-generated reply or an error message. - * - * @description Sends a single message to the agent and returns the agents' final response. - * - * @example - * const response = await fetch("/api/agent", { - * method: "POST", - * headers: { "Content-Type": "application/json" }, - * body: JSON.stringify({ userMessage: input }), - * }); - */ -export async function POST( - req: Request & { json: () => Promise }, -): Promise> { - try { - // 1️. Extract user message from the request body - const { userMessage } = await req.json(); - - // 2. Get the agent - const agent = await getOrInitializeAgent(); - - // 3.Start streaming the agent's response - const stream = await agent.stream( - { messages: [{ content: userMessage, role: "user" }] }, // The new message to send to the agent - { configurable: { thread_id: "AgentKit Discussion" } }, // Customizable thread ID for tracking conversations - ); - - // 4️. Process the streamed response chunks into a single message - let agentResponse = ""; - for await (const chunk of stream) { - if ("agent" in chunk) { - agentResponse += chunk.agent.messages[0].content; - } - } - - // 5️. Return the final response - return NextResponse.json({ response: agentResponse }); - } catch (error) { - console.error("Error processing request:", error); - return NextResponse.json({ error: "Failed to process message" }); - } -} diff --git a/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/evm/viem/prepare-agentkit.ts b/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/evm/viem/prepare-agentkit.ts new file mode 100644 index 000000000..a78ad1a7d --- /dev/null +++ b/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/evm/viem/prepare-agentkit.ts @@ -0,0 +1,119 @@ +import { + ActionProvider, + AgentKit, + cdpApiActionProvider, + erc20ActionProvider, + NETWORK_ID_TO_VIEM_CHAIN, + pythActionProvider, + ViemWalletProvider, + walletActionProvider, + WalletProvider, + wethActionProvider, +} from "@coinbase/agentkit"; +import fs from "fs"; +import { createWalletClient, Hex, http } from "viem"; +import { generatePrivateKey, privateKeyToAccount } from "viem/accounts"; + +/** + * AgentKit Integration Route + * + * This file is your gateway to integrating AgentKit with your product. + * It defines the interaction between your system and the AI agent, + * allowing you to configure the agent to suit your needs. + * + * # Key Steps to Customize Your Agent:** + * + * 1. Select your LLM: + * - Modify the `ChatOpenAI` instantiation to choose your preferred LLM. + * + * 2. Set up your WalletProvider: + * - Learn more: https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#evm-wallet-providers + * + * 3️. Set up your ActionProviders: + * - ActionProviders define what your agent can do. + * - Choose from built-in providers or create your own: + * - Built-in: https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#action-providers + * - Custom: https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#creating-an-action-provider + * + * 4. Instantiate your Agent: + * - Pass the LLM, tools, and memory into `createReactAgent()` to bring your agent to life. + * + * # Next Steps: + * - Explore the AgentKit README: https://github.com/coinbase/agentkit + * - Learn more about available WalletProviders & ActionProviders. + * - Experiment with custom ActionProviders for your unique use case. + * + * ## Want to contribute? + * Join us in shaping AgentKit! Check out the contribution guide: + * - https://github.com/coinbase/agentkit/blob/main/CONTRIBUTING.md + * - https://discord.gg/CDP + */ + +// Configure a file to persist a user's private key if none provided +const WALLET_DATA_FILE = "wallet_data.txt"; + +/** + * Prepares the AgentKit and WalletProvider. + * + * @function prepareAgentkitAndWalletProvider + * @returns {Promise<{ agentkit: AgentKit, walletProvider: WalletProvider }>} The initialized AI agent. + * + * @description Handles agent setup + * + * @throws {Error} If the agent initialization fails. + */ +export async function prepareAgentkitAndWalletProvider(): Promise<{ agentkit: AgentKit, walletProvider: WalletProvider }> { + try { + // Initialize WalletProvider: https://docs.cdp.coinbase.com/agentkit/docs/wallet-management + let privateKey = process.env.PRIVATE_KEY as Hex; + if (!privateKey) { + if (fs.existsSync(WALLET_DATA_FILE)) { + privateKey = JSON.parse(fs.readFileSync(WALLET_DATA_FILE, "utf8")).privateKey; + console.info("Found private key in wallet_data.txt"); + } else { + privateKey = generatePrivateKey(); + fs.writeFileSync(WALLET_DATA_FILE, JSON.stringify({ privateKey })); + console.log("Created new private key and saved to wallet_data.txt"); + console.log( + "We recommend you save this private key to your .env file and delete wallet_data.txt afterwards.", + ); + } + } + + const account = privateKeyToAccount(privateKey); + const networkId = process.env.NETWORK_ID as string; + + const client = createWalletClient({ + account, + chain: NETWORK_ID_TO_VIEM_CHAIN[networkId], + transport: http(), + }); + const walletProvider = new ViemWalletProvider(client); + + // Initialize AgentKit: https://docs.cdp.coinbase.com/agentkit/docs/agent-actions + const actionProviders: ActionProvider[] = [ + wethActionProvider(), + pythActionProvider(), + walletActionProvider(), + erc20ActionProvider(), + ]; + const canUseCdpApi = process.env.CDP_API_KEY_NAME && process.env.CDP_API_KEY_PRIVATE_KEY; + if (canUseCdpApi) { + actionProviders.push( + cdpApiActionProvider({ + apiKeyName: process.env.CDP_API_KEY_NAME, + apiKeyPrivateKey: process.env.CDP_API_KEY_PRIVATE_KEY, + }), + ); + } + const agentkit = await AgentKit.from({ + walletProvider, + actionProviders, + }); + + return { agentkit, walletProvider }; + } catch (error) { + console.error("Error initializing agent:", error); + throw new Error("Failed to initialize agent"); + } +} diff --git a/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/svm/privy/prepare-agentkit.ts b/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/svm/privy/prepare-agentkit.ts new file mode 100644 index 000000000..c0af16477 --- /dev/null +++ b/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/svm/privy/prepare-agentkit.ts @@ -0,0 +1,112 @@ +import { + ActionProvider, + AgentKit, + cdpApiActionProvider, + jupiterActionProvider, + PrivyWalletConfig, + PrivyWalletProvider, + splActionProvider, + walletActionProvider, + WalletProvider, +} from "@coinbase/agentkit"; +import fs from "fs"; + +/** + * AgentKit Integration Route + * + * This file is your gateway to integrating AgentKit with your product. + * It defines the interaction between your system and the AI agent, + * allowing you to configure the agent to suit your needs. + * + * # Key Steps to Customize Your Agent:** + * + * 1. Select your LLM: + * - Modify the `ChatOpenAI` instantiation to choose your preferred LLM. + * + * 2. Set up your WalletProvider: + * - Learn more: https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#evm-wallet-providers + * + * 3️. Set up your ActionProviders: + * - ActionProviders define what your agent can do. + * - Choose from built-in providers or create your own: + * - Built-in: https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#action-providers + * - Custom: https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#creating-an-action-provider + * + * 4. Instantiate your Agent: + * - Pass the LLM, tools, and memory into `createReactAgent()` to bring your agent to life. + * + * # Next Steps: + * - Explore the AgentKit README: https://github.com/coinbase/agentkit + * - Learn more about available WalletProviders & ActionProviders. + * - Experiment with custom ActionProviders for your unique use case. + * + * ## Want to contribute? + * Join us in shaping AgentKit! Check out the contribution guide: + * - https://github.com/coinbase/agentkit/blob/main/CONTRIBUTING.md + * - https://discord.gg/CDP + */ + +// Configure a file to persist the agent's Prviy Wallet Data +const WALLET_DATA_FILE = "wallet_data.txt"; + +/** + * Prepares the AgentKit and WalletProvider. + * + * @function prepareAgentkitAndWalletProvider + * @returns {Promise<{ agentkit: AgentKit, walletProvider: WalletProvider }>} The initialized AI agent. + * + * @description Handles agent setup + * + * @throws {Error} If the agent initialization fails. + */ +export async function prepareAgentkitAndWalletProvider(): Promise<{ agentkit: AgentKit, walletProvider: WalletProvider }> { + try { + // Initialize WalletProvider: https://docs.cdp.coinbase.com/agentkit/docs/wallet-management + const config: PrivyWalletConfig = { + appId: process.env.PRIVY_APP_ID as string, + appSecret: process.env.PRIVY_APP_SECRET as string, + walletId: process.env.PRIVY_WALLET_ID as string, + authorizationPrivateKey: process.env.PRIVY_WALLET_AUTHORIZATION_PRIVATE_KEY, + authorizationKeyId: process.env.PRIVY_WALLET_AUTHORIZATION_KEY_ID, + chainType: "solana", + networkId: process.env.NETWORK_ID, + }; + // Try to load saved wallet data + if (fs.existsSync(WALLET_DATA_FILE)) { + const savedWallet = JSON.parse(fs.readFileSync(WALLET_DATA_FILE, "utf8")); + config.walletId = savedWallet.walletId; + config.authorizationPrivateKey = savedWallet.authorizationPrivateKey; + config.networkId = savedWallet.networkId; + } + const walletProvider = await PrivyWalletProvider.configureWithWallet(config); + + // Initialize AgentKit: https://docs.cdp.coinbase.com/agentkit/docs/agent-actions + const actionProviders: ActionProvider[] = [ + walletActionProvider(), + splActionProvider(), + jupiterActionProvider(), + ]; + const canUseCdpApi = process.env.CDP_API_KEY_NAME && process.env.CDP_API_KEY_PRIVATE_KEY; + if (canUseCdpApi) { + actionProviders.push( + cdpApiActionProvider({ + apiKeyName: process.env.CDP_API_KEY_NAME, + apiKeyPrivateKey: process.env.CDP_API_KEY_PRIVATE_KEY, + }), + ); + } + const agentkit = await AgentKit.from({ + walletProvider, + actionProviders, + }); + + // Save wallet data + const exportedWallet = walletProvider.exportWallet(); + fs.writeFileSync(WALLET_DATA_FILE, JSON.stringify(exportedWallet)); + + return { agentkit, walletProvider }; + } catch (error) { + console.error("Error initializing agent:", error); + throw new Error("Failed to initialize agent"); + } +} diff --git a/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/svm/solanaKeypair/prepare-agentkit.ts b/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/svm/solanaKeypair/prepare-agentkit.ts new file mode 100644 index 000000000..a97a92f0f --- /dev/null +++ b/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/svm/solanaKeypair/prepare-agentkit.ts @@ -0,0 +1,118 @@ +import { + ActionProvider, + AgentKit, + cdpApiActionProvider, + jupiterActionProvider, + SOLANA_NETWORK_ID, + SolanaKeypairWalletProvider, + splActionProvider, + walletActionProvider, + WalletProvider, +} from "@coinbase/agentkit"; +import { Keypair } from "@solana/web3.js"; +import bs58 from "bs58"; +import fs from "fs"; +/** + * AgentKit Integration Route + * + * This file is your gateway to integrating AgentKit with your product. + * It defines the interaction between your system and the AI agent, + * allowing you to configure the agent to suit your needs. + * + * # Key Steps to Customize Your Agent:** + * + * 1. Select your LLM: + * - Modify the `ChatOpenAI` instantiation to choose your preferred LLM. + * + * 2. Set up your WalletProvider: + * - Learn more: https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#evm-wallet-providers + * + * 3️. Set up your ActionProviders: + * - ActionProviders define what your agent can do. + * - Choose from built-in providers or create your own: + * - Built-in: https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#action-providers + * - Custom: https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#creating-an-action-provider + * + * 4. Instantiate your Agent: + * - Pass the LLM, tools, and memory into `createReactAgent()` to bring your agent to life. + * + * # Next Steps: + * - Explore the AgentKit README: https://github.com/coinbase/agentkit + * - Learn more about available WalletProviders & ActionProviders. + * - Experiment with custom ActionProviders for your unique use case. + * + * ## Want to contribute? + * Join us in shaping AgentKit! Check out the contribution guide: + * - https://github.com/coinbase/agentkit/blob/main/CONTRIBUTING.md + * - https://discord.gg/CDP + */ + +// Configure a file to persist a user's private key if none provided +const WALLET_DATA_FILE = "wallet_data.txt"; + +/** + * Prepares the AgentKit and WalletProvider. + * + * @function prepareAgentkitAndWalletProvider + * @returns {Promise<{ agentkit: AgentKit, walletProvider: WalletProvider }>} The initialized AI agent. + * + * @description Handles agent setup + * + * @throws {Error} If the agent initialization fails. + */ +export async function prepareAgentkitAndWalletProvider(): Promise<{ agentkit: AgentKit, walletProvider: WalletProvider }> { + try { + // Setup Private Key + let privateKey = process.env.SOLANA_PRIVATE_KEY as string; + if (!privateKey) { + if (fs.existsSync(WALLET_DATA_FILE)) { + privateKey = JSON.parse(fs.readFileSync(WALLET_DATA_FILE, "utf8")).privateKey; + console.info("Found private key in wallet_data.txt"); + } else { + const keypair = Keypair.generate(); + privateKey = bs58.encode(keypair.secretKey); + fs.writeFileSync(WALLET_DATA_FILE, JSON.stringify({ privateKey })); + console.log("Created new private key and saved to wallet_data.txt"); + console.log( + "We recommend you save this private key to your .env file and delete wallet_data.txt afterwards.", + ); + } + } + + // Initialize WalletProvider: https://docs.cdp.coinbase.com/agentkit/docs/wallet-management + // Configure Solana Keypair Wallet Provider + const rpcUrl = process.env.SOLANA_RPC_URL; + let walletProvider: SolanaKeypairWalletProvider; + if (rpcUrl) { + walletProvider = await SolanaKeypairWalletProvider.fromRpcUrl(rpcUrl, privateKey); + } else { + const network = (process.env.NETWORK_ID ?? "solana-devnet") as SOLANA_NETWORK_ID; + walletProvider = await SolanaKeypairWalletProvider.fromNetwork(network, privateKey); + } + + // Initialize AgentKit: https://docs.cdp.coinbase.com/agentkit/docs/agent-actions + const actionProviders: ActionProvider[] = [ + walletActionProvider(), + splActionProvider(), + jupiterActionProvider(), + ]; + const canUseCdpApi = process.env.CDP_API_KEY_NAME && process.env.CDP_API_KEY_PRIVATE_KEY; + if (canUseCdpApi) { + actionProviders.push( + cdpApiActionProvider({ + apiKeyName: process.env.CDP_API_KEY_NAME, + apiKeyPrivateKey: process.env.CDP_API_KEY_PRIVATE_KEY, + }), + ); + } + const agentkit = await AgentKit.from({ + walletProvider, + actionProviders, + }); + + return { agentkit, walletProvider }; + } catch (error) { + console.error("Error initializing agent:", error); + throw new Error("Failed to initialize agent"); + } +} diff --git a/typescript/create-onchain-agent/templates/next/app/api/agent/custom-evm/viem/route.ts b/typescript/create-onchain-agent/templates/next/app/api/agent/custom-evm/viem/route.ts deleted file mode 100644 index c3c71be7c..000000000 --- a/typescript/create-onchain-agent/templates/next/app/api/agent/custom-evm/viem/route.ts +++ /dev/null @@ -1,220 +0,0 @@ -import { AgentRequest, AgentResponse } from "@/app/types/api"; -import { - ActionProvider, - AgentKit, - cdpApiActionProvider, - erc20ActionProvider, - pythActionProvider, - ViemWalletProvider, - walletActionProvider, - wethActionProvider, -} from "@coinbase/agentkit"; -import { getLangChainTools } from "@coinbase/agentkit-langchain"; -import { MemorySaver } from "@langchain/langgraph"; -import { createReactAgent } from "@langchain/langgraph/prebuilt"; -import { ChatOpenAI } from "@langchain/openai"; -import fs from "fs"; -import { NextResponse } from "next/server"; -import { createWalletClient, http } from "viem"; -import { generatePrivateKey, privateKeyToAccount } from "viem/accounts"; - -/** - * AgentKit Integration Route - * - * This file is your gateway to integrating AgentKit with your product. - * It defines the interaction between your system and the AI agent, - * allowing you to configure the agent to suit your needs. - * - * # Key Steps to Customize Your Agent:** - * - * 1. Select your LLM: - * - Modify the `ChatOpenAI` instantiation to choose your preferred LLM. - * - * 2. Set up your WalletProvider: - * - Learn more: https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#evm-wallet-providers - * - * 3️. Set up your ActionProviders: - * - ActionProviders define what your agent can do. - * - Choose from built-in providers or create your own: - * - Built-in: https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#action-providers - * - Custom: https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#creating-an-action-provider - * - * 4. Instantiate your Agent: - * - Pass the LLM, tools, and memory into `createReactAgent()` to bring your agent to life. - * - * # Next Steps: - * - Explore the AgentKit README: https://github.com/coinbase/agentkit - * - Learn more about available WalletProviders & ActionProviders. - * - Experiment with custom ActionProviders for your unique use case. - * - * ## Want to contribute? - * Join us in shaping AgentKit! Check out the contribution guide: - * - https://github.com/coinbase/agentkit/blob/main/CONTRIBUTING.md - * - https://discord.gg/CDP - */ - -// The agent -let agent: ReturnType; - -// Configure a file to persist a user's private key if none provided -const WALLET_DATA_FILE = "wallet_data.txt"; - -/** - * Initializes and returns an instance of the AI agent. - * If an agent instance already exists, it returns the existing one. - * - * @function getOrInitializeAgent - * @returns {Promise>} The initialized AI agent. - * - * @description Handles agent setup - * - * @throws {Error} If the agent initialization fails. - */ -async function getOrInitializeAgent(): Promise> { - // If agent has already been initialized, return it - if (agent) { - return agent; - } - - try { - // Initialize LLM: https://platform.openai.com/docs/models#gpt-4o - const llm = new ChatOpenAI({ model: "gpt-4o-mini" }); - - // Initialize WalletProvider: https://docs.cdp.coinbase.com/agentkit/docs/wallet-management - let privateKey = process.env.PRIVATE_KEY as `0x${string}`; - if (!privateKey) { - if (fs.existsSync(WALLET_DATA_FILE)) { - privateKey = JSON.parse(fs.readFileSync(WALLET_DATA_FILE, "utf8")).privateKey; - console.info("Found private key in wallet_data.txt"); - } else { - privateKey = generatePrivateKey(); - fs.writeFileSync(WALLET_DATA_FILE, JSON.stringify({ privateKey })); - console.log("Created new private key and saved to wallet_data.txt"); - console.log( - "We recommend you save this private key to your .env file and delete wallet_data.txt afterwards.", - ); - } - } - const account = privateKeyToAccount(privateKey); - - const rpcUrl = process.env.RPC_URL as string; - const chainId = process.env.CHAIN_ID as string; - const client = createWalletClient({ - account, - // Customize the chain metadata to match your custom chain - chain: { - id: parseInt(chainId), - rpcUrls: { - default: { - http: [rpcUrl], - }, - }, - name: "Custom Chain", - nativeCurrency: { - name: "Ether", - symbol: "ETH", - decimals: 18, - }, - }, - transport: http(), - }); - const walletProvider = new ViemWalletProvider(client); - - // Initialize AgentKit: https://docs.cdp.coinbase.com/agentkit/docs/agent-actions - const actionProviders: ActionProvider[] = [ - wethActionProvider(), - pythActionProvider(), - walletActionProvider(), - erc20ActionProvider(), - ]; - const canUseCdpApi = process.env.CDP_API_KEY_NAME && process.env.CDP_API_KEY_PRIVATE_KEY; - if (canUseCdpApi) { - actionProviders.push( - cdpApiActionProvider({ - apiKeyName: process.env.CDP_API_KEY_NAME, - apiKeyPrivateKey: process.env.CDP_API_KEY_PRIVATE_KEY, - }), - ); - } - const agentkit = await AgentKit.from({ - walletProvider, - actionProviders, - }); - const tools = await getLangChainTools(agentkit); - const memory = new MemorySaver(); - - // Initialize Agent - const canUseFaucet = walletProvider.getNetwork().networkId == "base-sepolia" && canUseCdpApi; - const faucetMessage = `If you ever need funds, you can request them from the faucet.`; - const cantUseFaucetMessage = `If you need funds, you can provide your wallet details and request funds from the user.`; - agent = createReactAgent({ - llm, - tools, - checkpointSaver: memory, - messageModifier: ` - You are a helpful agent that can interact onchain using the Coinbase Developer Platform AgentKit. You are - empowered to interact onchain using your tools. ${canUseFaucet ? faucetMessage : cantUseFaucetMessage}. - Before executing your first action, get the wallet details to see what network - you're on. 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 CDP SDK + Agentkit, recommend they go to - docs.cdp.coinbase.com for more information. Be concise and helpful with your responses. Refrain from - restating your tools' descriptions unless it is explicitly requested. - `, - }); - - return agent; - } catch (error) { - console.error("Error initializing agent:", error); - throw new Error("Failed to initialize agent"); - } -} - -/** - * Handles incoming POST requests to interact with the AgentKit-powered AI agent. - * This function processes user messages and streams responses from the agent. - * - * @function POST - * @param {Request & { json: () => Promise }} req - The incoming request object containing the user message. - * @returns {Promise>} JSON response containing the AI-generated reply or an error message. - * - * @description Sends a single message to the agent and returns the agents' final response. - * - * @example - * const response = await fetch("/api/agent", { - * method: "POST", - * headers: { "Content-Type": "application/json" }, - * body: JSON.stringify({ userMessage: input }), - * }); - */ -export async function POST( - req: Request & { json: () => Promise }, -): Promise> { - try { - // 1️. Extract user message from the request body - const { userMessage } = await req.json(); - - // 2. Get the agent - const agent = await getOrInitializeAgent(); - - // 3.Start streaming the agent's response - const stream = await agent.stream( - { messages: [{ content: userMessage, role: "user" }] }, // The new message to send to the agent - { configurable: { thread_id: "AgentKit Discussion" } }, // Customizable thread ID for tracking conversations - ); - - // 4️. Process the streamed response chunks into a single message - let agentResponse = ""; - for await (const chunk of stream) { - if ("agent" in chunk) { - agentResponse += chunk.agent.messages[0].content; - } - } - - // 5️. Return the final response - return NextResponse.json({ response: agentResponse }); - } catch (error) { - console.error("Error processing request:", error); - return NextResponse.json({ error: "Failed to process message" }); - } -} diff --git a/typescript/create-onchain-agent/templates/next/app/api/agent/evm/cdp/route.ts b/typescript/create-onchain-agent/templates/next/app/api/agent/evm/cdp/route.ts deleted file mode 100644 index 7473039c8..000000000 --- a/typescript/create-onchain-agent/templates/next/app/api/agent/evm/cdp/route.ts +++ /dev/null @@ -1,200 +0,0 @@ -import { NextResponse } from "next/server"; -import { - AgentKit, - cdpApiActionProvider, - cdpWalletActionProvider, - CdpWalletProvider, - erc20ActionProvider, - pythActionProvider, - walletActionProvider, - wethActionProvider, -} from "@coinbase/agentkit"; -import { getLangChainTools } from "@coinbase/agentkit-langchain"; -import { ChatOpenAI } from "@langchain/openai"; -import { MemorySaver } from "@langchain/langgraph"; -import { createReactAgent } from "@langchain/langgraph/prebuilt"; -import { AgentRequest, AgentResponse } from "@/app/types/api"; -import * as fs from "fs"; - -/** - * AgentKit Integration Route - * - * This file is your gateway to integrating AgentKit with your product. - * It defines the interaction between your system and the AI agent, - * allowing you to configure the agent to suit your needs. - * - * # Key Steps to Customize Your Agent:** - * - * 1. Select your LLM: - * - Modify the `ChatOpenAI` instantiation to choose your preferred LLM. - * - * 2. Set up your WalletProvider: - * - Learn more: https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#evm-wallet-providers - * - * 3️. Set up your ActionProviders: - * - ActionProviders define what your agent can do. - * - Choose from built-in providers or create your own: - * - Built-in: https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#action-providers - * - Custom: https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#creating-an-action-provider - * - * 4. Instantiate your Agent: - * - Pass the LLM, tools, and memory into `createReactAgent()` to bring your agent to life. - * - * # Next Steps: - * - Explore the AgentKit README: https://github.com/coinbase/agentkit - * - Learn more about available WalletProviders & ActionProviders. - * - Experiment with custom ActionProviders for your unique use case. - * - * ## Want to contribute? - * Join us in shaping AgentKit! Check out the contribution guide: - * - https://github.com/coinbase/agentkit/blob/main/CONTRIBUTING.md - * - https://discord.gg/CDP - */ - -// The agent -let agent: ReturnType; - -// Configure a file to persist the agent's CDP MPC Wallet Data -const WALLET_DATA_FILE = "wallet_data.txt"; - -/** - * Initializes and returns an instance of the AI agent. - * If an agent instance already exists, it returns the existing one. - * - * @function getOrInitializeAgent - * @returns {Promise>} The initialized AI agent. - * - * @description Handles agent setup - * - * @throws {Error} If the agent initialization fails. - */ -async function getOrInitializeAgent(): Promise> { - // If agent has already been initialized, return it - if (agent) { - return agent; - } - - try { - // Initialize LLM: https://platform.openai.com/docs/models#gpt-4o - const llm = new ChatOpenAI({ model: "gpt-4o-mini" }); - - let walletDataStr: string | null = null; - - // Read existing wallet data if available - if (fs.existsSync(WALLET_DATA_FILE)) { - try { - walletDataStr = fs.readFileSync(WALLET_DATA_FILE, "utf8"); - } catch (error) { - console.error("Error reading wallet data:", error); - // Continue without wallet data - } - } - - // Initialize WalletProvider: https://docs.cdp.coinbase.com/agentkit/docs/wallet-management - const walletProvider = await CdpWalletProvider.configureWithWallet({ - apiKeyName: process.env.CDP_API_KEY_NAME, - apiKeyPrivateKey: process.env.CDP_API_KEY_PRIVATE_KEY, - networkId: process.env.NETWORK_ID || "base-sepolia", - cdpWalletData: walletDataStr || undefined, - }); - - // Initialize AgentKit: https://docs.cdp.coinbase.com/agentkit/docs/agent-actions - const agentkit = await AgentKit.from({ - walletProvider, - actionProviders: [ - wethActionProvider(), - pythActionProvider(), - walletActionProvider(), - erc20ActionProvider(), - cdpApiActionProvider({ - apiKeyName: process.env.CDP_API_KEY_NAME, - apiKeyPrivateKey: process.env.CDP_API_KEY_PRIVATE_KEY, - }), - cdpWalletActionProvider({ - apiKeyName: process.env.CDP_API_KEY_NAME, - apiKeyPrivateKey: process.env.CDP_API_KEY_PRIVATE_KEY, - }), - ], - }); - const tools = await getLangChainTools(agentkit); - const memory = new MemorySaver(); - - // Initialize Agent - const canUseFaucet = walletProvider.getNetwork().networkId == "base-sepolia"; - const faucetMessage = `If you ever need funds, you can request them from the faucet.`; - const cantUseFaucetMessage = `If you need funds, you can provide your wallet details and request funds from the user.`; - agent = createReactAgent({ - llm, - tools, - checkpointSaver: memory, - messageModifier: ` - You are a helpful agent that can interact onchain using the Coinbase Developer Platform AgentKit. You are - empowered to interact onchain using your tools. ${canUseFaucet ? faucetMessage : cantUseFaucetMessage}. - Before executing your first action, get the wallet details to see what network - you're on. 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 CDP SDK + Agentkit, recommend they go to - docs.cdp.coinbase.com for more information. Be concise and helpful with your responses. Refrain from - restating your tools' descriptions unless it is explicitly requested. - `, - }); - - // Save wallet data - const exportedWallet = await walletProvider.exportWallet(); - fs.writeFileSync(WALLET_DATA_FILE, JSON.stringify(exportedWallet)); - - return agent; - } catch (error) { - console.error("Error initializing agent:", error); - throw new Error("Failed to initialize agent"); - } -} - -/** - * Handles incoming POST requests to interact with the AgentKit-powered AI agent. - * This function processes user messages and streams responses from the agent. - * - * @function POST - * @param {Request & { json: () => Promise }} req - The incoming request object containing the user message. - * @returns {Promise>} JSON response containing the AI-generated reply or an error message. - * - * @description Sends a single message to the agent and returns the agents' final response. - * - * @example - * const response = await fetch("/api/agent", { - * method: "POST", - * headers: { "Content-Type": "application/json" }, - * body: JSON.stringify({ userMessage: input }), - * }); - */ -export async function POST( - req: Request & { json: () => Promise }, -): Promise> { - try { - // 1️. Extract user message from the request body - const { userMessage } = await req.json(); - - // 2. Get the agent - const agent = await getOrInitializeAgent(); - - // 3.Start streaming the agent's response - const stream = await agent.stream( - { messages: [{ content: userMessage, role: "user" }] }, // The new message to send to the agent - { configurable: { thread_id: "AgentKit Discussion" } }, // Customizable thread ID for tracking conversations - ); - - // 4️. Process the streamed response chunks into a single message - let agentResponse = ""; - for await (const chunk of stream) { - if ("agent" in chunk) { - agentResponse += chunk.agent.messages[0].content; - } - } - - // 5️. Return the final response - return NextResponse.json({ response: agentResponse }); - } catch (error) { - console.error("Error processing request:", error); - return NextResponse.json({ error: "Failed to process message" }); - } -} diff --git a/typescript/create-onchain-agent/templates/next/app/api/agent/evm/privy/route.ts b/typescript/create-onchain-agent/templates/next/app/api/agent/evm/privy/route.ts deleted file mode 100644 index d814019da..000000000 --- a/typescript/create-onchain-agent/templates/next/app/api/agent/evm/privy/route.ts +++ /dev/null @@ -1,209 +0,0 @@ -import { AgentRequest, AgentResponse } from "@/app/types/api"; -import { - ActionProvider, - AgentKit, - cdpApiActionProvider, - erc20ActionProvider, - PrivyWalletConfig, - PrivyWalletProvider, - pythActionProvider, - walletActionProvider, - wethActionProvider, -} from "@coinbase/agentkit"; -import { getLangChainTools } from "@coinbase/agentkit-langchain"; -import { MemorySaver } from "@langchain/langgraph"; -import { createReactAgent } from "@langchain/langgraph/prebuilt"; -import { ChatOpenAI } from "@langchain/openai"; -import { NextResponse } from "next/server"; -import fs from "fs"; - -/** - * AgentKit Integration Route - * - * This file is your gateway to integrating AgentKit with your product. - * It defines the interaction between your system and the AI agent, - * allowing you to configure the agent to suit your needs. - * - * # Key Steps to Customize Your Agent:** - * - * 1. Select your LLM: - * - Modify the `ChatOpenAI` instantiation to choose your preferred LLM. - * - * 2. Set up your WalletProvider: - * - Learn more: https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#evm-wallet-providers - * - * 3️. Set up your ActionProviders: - * - ActionProviders define what your agent can do. - * - Choose from built-in providers or create your own: - * - Built-in: https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#action-providers - * - Custom: https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#creating-an-action-provider - * - * 4. Instantiate your Agent: - * - Pass the LLM, tools, and memory into `createReactAgent()` to bring your agent to life. - * - * # Next Steps: - * - Explore the AgentKit README: https://github.com/coinbase/agentkit - * - Learn more about available WalletProviders & ActionProviders. - * - Experiment with custom ActionProviders for your unique use case. - * - * ## Want to contribute? - * Join us in shaping AgentKit! Check out the contribution guide: - * - https://github.com/coinbase/agentkit/blob/main/CONTRIBUTING.md - * - https://discord.gg/CDP - */ - -// The agent -let agent: ReturnType; - -// Configure a file to persist the agent's Privy Wallet Data -const WALLET_DATA_FILE = "wallet_data.txt"; - -/** - * Initializes and returns an instance of the AI agent. - * If an agent instance already exists, it returns the existing one. - * - * @function getOrInitializeAgent - * @returns {Promise>} The initialized AI agent. - * - * @description Handles agent setup - * - * @throws {Error} If the agent initialization fails. - */ -async function getOrInitializeAgent(): Promise> { - // If agent has already been initialized, return it - if (agent) { - return agent; - } - - try { - // Initialize LLM: https://platform.openai.com/docs/models#gpt-4o - const llm = new ChatOpenAI({ model: "gpt-4o-mini" }); - - // Initialize WalletProvider: https://docs.cdp.coinbase.com/agentkit/docs/wallet-management - const config: PrivyWalletConfig = { - appId: process.env.PRIVY_APP_ID as string, - appSecret: process.env.PRIVY_APP_SECRET as string, - walletId: process.env.PRIVY_WALLET_ID as string, - chainId: process.env.CHAIN_ID, - authorizationPrivateKey: process.env.PRIVY_WALLET_AUTHORIZATION_PRIVATE_KEY, - authorizationKeyId: process.env.PRIVY_WALLET_AUTHORIZATION_KEY_ID, - }; - // Try to load saved wallet data - if (fs.existsSync(WALLET_DATA_FILE)) { - const savedWallet = JSON.parse(fs.readFileSync(WALLET_DATA_FILE, "utf8")); - config.walletId = savedWallet.walletId; - config.authorizationPrivateKey = savedWallet.authorizationPrivateKey; - - if (savedWallet.chainId) { - console.log("Found chainId in wallet_data.txt:", savedWallet.chainId); - config.chainId = savedWallet.chainId; - } - } - if (!config.chainId) { - console.log("Warning: CHAIN_ID not set, defaulting to 84532 (base-sepolia)"); - config.chainId = "84532"; - } - const walletProvider = await PrivyWalletProvider.configureWithWallet(config); - - // Initialize AgentKit: https://docs.cdp.coinbase.com/agentkit/docs/agent-actions - const actionProviders: ActionProvider[] = [ - wethActionProvider(), - pythActionProvider(), - walletActionProvider(), - erc20ActionProvider(), - ]; - const canUseCdpApi = process.env.CDP_API_KEY_NAME && process.env.CDP_API_KEY_PRIVATE_KEY; - if (canUseCdpApi) { - actionProviders.push( - cdpApiActionProvider({ - apiKeyName: process.env.CDP_API_KEY_NAME, - apiKeyPrivateKey: process.env.CDP_API_KEY_PRIVATE_KEY, - }), - ); - } - const agentkit = await AgentKit.from({ - walletProvider, - actionProviders, - }); - const tools = await getLangChainTools(agentkit); - const memory = new MemorySaver(); - - // Initialize Agent - const canUseFaucet = walletProvider.getNetwork().networkId == "base-sepolia" && canUseCdpApi; - const faucetMessage = `If you ever need funds, you can request them from the faucet.`; - const cantUseFaucetMessage = `If you need funds, you can provide your wallet details and request funds from the user.`; - agent = createReactAgent({ - llm, - tools, - checkpointSaver: memory, - messageModifier: ` - You are a helpful agent that can interact onchain using the Coinbase Developer Platform AgentKit. You are - empowered to interact onchain using your tools. ${canUseFaucet ? faucetMessage : cantUseFaucetMessage}. - Before executing your first action, get the wallet details to see what network - you're on. 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 CDP SDK + Agentkit, recommend they go to - docs.cdp.coinbase.com for more information. Be concise and helpful with your responses. Refrain from - restating your tools' descriptions unless it is explicitly requested. - `, - }); - - // Save wallet data - const exportedWallet = walletProvider.exportWallet(); - fs.writeFileSync(WALLET_DATA_FILE, JSON.stringify(exportedWallet)); - - return agent; - } catch (error) { - console.error("Error initializing agent:", error); - throw new Error("Failed to initialize agent"); - } -} - -/** - * Handles incoming POST requests to interact with the AgentKit-powered AI agent. - * This function processes user messages and streams responses from the agent. - * - * @function POST - * @param {Request & { json: () => Promise }} req - The incoming request object containing the user message. - * @returns {Promise>} JSON response containing the AI-generated reply or an error message. - * - * @description Sends a single message to the agent and returns the agents' final response. - * - * @example - * const response = await fetch("/api/agent", { - * method: "POST", - * headers: { "Content-Type": "application/json" }, - * body: JSON.stringify({ userMessage: input }), - * }); - */ -export async function POST( - req: Request & { json: () => Promise }, -): Promise> { - try { - // 1️. Extract user message from the request body - const { userMessage } = await req.json(); - - // 2. Get the agent - const agent = await getOrInitializeAgent(); - - // 3.Start streaming the agent's response - const stream = await agent.stream( - { messages: [{ content: userMessage, role: "user" }] }, // The new message to send to the agent - { configurable: { thread_id: "AgentKit Discussion" } }, // Customizable thread ID for tracking conversations - ); - - // 4️. Process the streamed response chunks into a single message - let agentResponse = ""; - for await (const chunk of stream) { - if ("agent" in chunk) { - agentResponse += chunk.agent.messages[0].content; - } - } - - // 5️. Return the final response - return NextResponse.json({ response: agentResponse }); - } catch (error) { - console.error("Error processing request:", error); - return NextResponse.json({ error: "Failed to process message" }); - } -} diff --git a/typescript/create-onchain-agent/templates/next/app/api/agent/evm/viem/route.ts b/typescript/create-onchain-agent/templates/next/app/api/agent/evm/viem/route.ts deleted file mode 100644 index 75c68d3c7..000000000 --- a/typescript/create-onchain-agent/templates/next/app/api/agent/evm/viem/route.ts +++ /dev/null @@ -1,207 +0,0 @@ -import { NextResponse } from "next/server"; -import { - ActionProvider, - AgentKit, - cdpApiActionProvider, - erc20ActionProvider, - NETWORK_ID_TO_VIEM_CHAIN, - pythActionProvider, - ViemWalletProvider, - walletActionProvider, - wethActionProvider, -} from "@coinbase/agentkit"; -import { getLangChainTools } from "@coinbase/agentkit-langchain"; -import { ChatOpenAI } from "@langchain/openai"; -import { MemorySaver } from "@langchain/langgraph"; -import { createReactAgent } from "@langchain/langgraph/prebuilt"; -import { AgentRequest, AgentResponse } from "@/app/types/api"; -import { createWalletClient, Hex, http } from "viem"; -import { generatePrivateKey, privateKeyToAccount } from "viem/accounts"; -import fs from "fs"; - -/** - * AgentKit Integration Route - * - * This file is your gateway to integrating AgentKit with your product. - * It defines the interaction between your system and the AI agent, - * allowing you to configure the agent to suit your needs. - * - * # Key Steps to Customize Your Agent:** - * - * 1. Select your LLM: - * - Modify the `ChatOpenAI` instantiation to choose your preferred LLM. - * - * 2. Set up your WalletProvider: - * - Learn more: https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#evm-wallet-providers - * - * 3️. Set up your ActionProviders: - * - ActionProviders define what your agent can do. - * - Choose from built-in providers or create your own: - * - Built-in: https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#action-providers - * - Custom: https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#creating-an-action-provider - * - * 4. Instantiate your Agent: - * - Pass the LLM, tools, and memory into `createReactAgent()` to bring your agent to life. - * - * # Next Steps: - * - Explore the AgentKit README: https://github.com/coinbase/agentkit - * - Learn more about available WalletProviders & ActionProviders. - * - Experiment with custom ActionProviders for your unique use case. - * - * ## Want to contribute? - * Join us in shaping AgentKit! Check out the contribution guide: - * - https://github.com/coinbase/agentkit/blob/main/CONTRIBUTING.md - * - https://discord.gg/CDP - */ - -// The agent -let agent: ReturnType; - -// Configure a file to persist a user's private key if none provided -const WALLET_DATA_FILE = "wallet_data.txt"; - -/** - * Initializes and returns an instance of the AI agent. - * If an agent instance already exists, it returns the existing one. - * - * @function getOrInitializeAgent - * @returns {Promise>} The initialized AI agent. - * - * @description Handles agent setup - * - * @throws {Error} If the agent initialization fails. - */ -async function getOrInitializeAgent(): Promise> { - // If agent has already been initialized, return it - if (agent) { - return agent; - } - - try { - // Initialize LLM: https://platform.openai.com/docs/models#gpt-4o - const llm = new ChatOpenAI({ model: "gpt-4o-mini" }); - - // Initialize WalletProvider: https://docs.cdp.coinbase.com/agentkit/docs/wallet-management - let privateKey = process.env.PRIVATE_KEY as Hex; - if (!privateKey) { - if (fs.existsSync(WALLET_DATA_FILE)) { - privateKey = JSON.parse(fs.readFileSync(WALLET_DATA_FILE, "utf8")).privateKey; - console.info("Found private key in wallet_data.txt"); - } else { - privateKey = generatePrivateKey(); - fs.writeFileSync(WALLET_DATA_FILE, JSON.stringify({ privateKey })); - console.log("Created new private key and saved to wallet_data.txt"); - console.log( - "We recommend you save this private key to your .env file and delete wallet_data.txt afterwards.", - ); - } - } - - const account = privateKeyToAccount(privateKey); - const networkId = process.env.NETWORK_ID as string; - - const client = createWalletClient({ - account, - chain: NETWORK_ID_TO_VIEM_CHAIN[networkId], - transport: http(), - }); - const walletProvider = new ViemWalletProvider(client); - - // Initialize AgentKit: https://docs.cdp.coinbase.com/agentkit/docs/agent-actions - const actionProviders: ActionProvider[] = [ - wethActionProvider(), - pythActionProvider(), - walletActionProvider(), - erc20ActionProvider(), - ]; - const canUseCdpApi = process.env.CDP_API_KEY_NAME && process.env.CDP_API_KEY_PRIVATE_KEY; - if (canUseCdpApi) { - actionProviders.push( - cdpApiActionProvider({ - apiKeyName: process.env.CDP_API_KEY_NAME, - apiKeyPrivateKey: process.env.CDP_API_KEY_PRIVATE_KEY, - }), - ); - } - const agentkit = await AgentKit.from({ - walletProvider, - actionProviders, - }); - const tools = await getLangChainTools(agentkit); - const memory = new MemorySaver(); - - // Initialize Agent - const canUseFaucet = walletProvider.getNetwork().networkId == "base-sepolia" && canUseCdpApi; - const faucetMessage = `If you ever need funds, you can request them from the faucet.`; - const cantUseFaucetMessage = `If you need funds, you can provide your wallet details and request funds from the user.`; - agent = createReactAgent({ - llm, - tools, - checkpointSaver: memory, - messageModifier: ` - You are a helpful agent that can interact onchain using the Coinbase Developer Platform AgentKit. You are - empowered to interact onchain using your tools. ${canUseFaucet ? faucetMessage : cantUseFaucetMessage}. - Before executing your first action, get the wallet details to see what network - you're on. 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 CDP SDK + Agentkit, recommend they go to - docs.cdp.coinbase.com for more information. Be concise and helpful with your responses. Refrain from - restating your tools' descriptions unless it is explicitly requested. - `, - }); - - return agent; - } catch (error) { - console.error("Error initializing agent:", error); - throw new Error("Failed to initialize agent"); - } -} - -/** - * Handles incoming POST requests to interact with the AgentKit-powered AI agent. - * This function processes user messages and streams responses from the agent. - * - * @function POST - * @param {Request & { json: () => Promise }} req - The incoming request object containing the user message. - * @returns {Promise>} JSON response containing the AI-generated reply or an error message. - * - * @description Sends a single message to the agent and returns the agents' final response. - * - * @example - * const response = await fetch("/api/agent", { - * method: "POST", - * headers: { "Content-Type": "application/json" }, - * body: JSON.stringify({ userMessage: input }), - * }); - */ -export async function POST( - req: Request & { json: () => Promise }, -): Promise> { - try { - // 1️. Extract user message from the request body - const { userMessage } = await req.json(); - - // 2. Get the agent - const agent = await getOrInitializeAgent(); - - // 3.Start streaming the agent's response - const stream = await agent.stream( - { messages: [{ content: userMessage, role: "user" }] }, // The new message to send to the agent - { configurable: { thread_id: "AgentKit Discussion" } }, // Customizable thread ID for tracking conversations - ); - - // 4️. Process the streamed response chunks into a single message - let agentResponse = ""; - for await (const chunk of stream) { - if ("agent" in chunk) { - agentResponse += chunk.agent.messages[0].content; - } - } - - // 5️. Return the final response - return NextResponse.json({ response: agentResponse }); - } catch (error) { - console.error("Error processing request:", error); - return NextResponse.json({ error: "Failed to process message" }); - } -} diff --git a/typescript/create-onchain-agent/templates/next/app/api/agent/framework/langchain/create-agent.ts b/typescript/create-onchain-agent/templates/next/app/api/agent/framework/langchain/create-agent.ts new file mode 100644 index 000000000..3edbdd5b9 --- /dev/null +++ b/typescript/create-onchain-agent/templates/next/app/api/agent/framework/langchain/create-agent.ts @@ -0,0 +1,61 @@ +import { getLangChainTools } from "@coinbase/agentkit-langchain"; +import { MemorySaver } from "@langchain/langgraph"; +import { createReactAgent } from "@langchain/langgraph/prebuilt"; +import { ChatOpenAI } from "@langchain/openai"; +import { prepareAgentkitAndWalletProvider } from "./prepare-agentkit"; + +// The agent +let agent: ReturnType; + +/** + * Initializes and returns an instance of the AI agent. + * If an agent instance already exists, it returns the existing one. + * + * @function getOrInitializeAgent + * @returns {Promise>} The initialized AI agent. + * + * @description Handles agent setup + * + * @throws {Error} If the agent initialization fails. + */ +export async function createAgent(): Promise> { + // If agent has already been initialized, return it + if (agent) { + return agent; + } + + try { + const { agentkit, walletProvider } = await prepareAgentkitAndWalletProvider(); + + // Initialize LLM: https://platform.openai.com/docs/models#gpt-4o + const llm = new ChatOpenAI({ model: "gpt-4o-mini" }); + + const tools = await getLangChainTools(agentkit); + const memory = new MemorySaver(); + + // Initialize Agent + const canUseFaucet = walletProvider.getNetwork().networkId == "base-sepolia"; + const faucetMessage = `If you ever need funds, you can request them from the faucet.`; + const cantUseFaucetMessage = `If you need funds, you can provide your wallet details and request funds from the user.`; + agent = createReactAgent({ + llm, + tools, + checkpointSaver: memory, + messageModifier: ` + You are a helpful agent that can interact onchain using the Coinbase Developer Platform AgentKit. You are + empowered to interact onchain using your tools. ${canUseFaucet ? faucetMessage : cantUseFaucetMessage}. + Before executing your first action, get the wallet details to see what network + you're on. 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 CDP SDK + Agentkit, recommend they go to + docs.cdp.coinbase.com for more information. Be concise and helpful with your responses. Refrain from + restating your tools' descriptions unless it is explicitly requested. + `, + }); + + return agent; + } catch (error) { + console.error("Error initializing agent:", error); + throw new Error("Failed to initialize agent"); + } +} \ No newline at end of file diff --git a/typescript/create-onchain-agent/templates/next/app/api/agent/framework/langchain/prepare-agentkit.ts b/typescript/create-onchain-agent/templates/next/app/api/agent/framework/langchain/prepare-agentkit.ts new file mode 100644 index 000000000..4ded11a39 --- /dev/null +++ b/typescript/create-onchain-agent/templates/next/app/api/agent/framework/langchain/prepare-agentkit.ts @@ -0,0 +1,19 @@ +import { + AgentKit, + WalletProvider +} from "@coinbase/agentkit"; + +/** + * A stub function that throws a "Not implemented" error. + * + * This is a placeholder function for the implementation that is selected. + * The actual implementation is selected by the cli user that generated this framework. + * + * @function prepareAgentkitAndWalletProvider + * @returns {Promise<{ agentkit: AgentKit, walletProvider: WalletProvider }>} The initialized AI agent. + * + * @throws {Error} Throws a "Not implemented" error. + */ +export async function prepareAgentkitAndWalletProvider(): Promise<{ agentkit: AgentKit, walletProvider: WalletProvider }> { + throw new Error("Not implemented"); +} diff --git a/typescript/create-onchain-agent/templates/next/app/api/agent/framework/langchain/route.ts b/typescript/create-onchain-agent/templates/next/app/api/agent/framework/langchain/route.ts new file mode 100644 index 000000000..238f5b885 --- /dev/null +++ b/typescript/create-onchain-agent/templates/next/app/api/agent/framework/langchain/route.ts @@ -0,0 +1,51 @@ +import { AgentRequest, AgentResponse } from "@/app/types/api"; +import { NextResponse } from "next/server"; +import { createAgent } from "./create-agent"; +/** + * Handles incoming POST requests to interact with the AgentKit-powered AI agent. + * This function processes user messages and streams responses from the agent. + * + * @function POST + * @param {Request & { json: () => Promise }} req - The incoming request object containing the user message. + * @returns {Promise>} JSON response containing the AI-generated reply or an error message. + * + * @description Sends a single message to the agent and returns the agents' final response. + * + * @example + * const response = await fetch("/api/agent", { + * method: "POST", + * headers: { "Content-Type": "application/json" }, + * body: JSON.stringify({ userMessage: input }), + * }); + */ +export async function POST( + req: Request & { json: () => Promise }, +): Promise> { + try { + // 1️. Extract user message from the request body + const { userMessage } = await req.json(); + + // 2. Get the agent + const agent = await createAgent(); + + // 3.Start streaming the agent's response + const stream = await agent.stream( + { messages: [{ content: userMessage, role: "user" }] }, // The new message to send to the agent + { configurable: { thread_id: "AgentKit Discussion" } }, // Customizable thread ID for tracking conversations + ); + + // 4️. Process the streamed response chunks into a single message + let agentResponse = ""; + for await (const chunk of stream) { + if ("agent" in chunk) { + agentResponse += chunk.agent.messages[0].content; + } + } + + // 5️. Return the final response + return NextResponse.json({ response: agentResponse }); + } catch (error) { + console.error("Error processing request:", error); + return NextResponse.json({ error: "Failed to process message" }); + } +} diff --git a/typescript/create-onchain-agent/templates/next/app/api/agent/framework/vercel-ai-sdk/create-agent.ts b/typescript/create-onchain-agent/templates/next/app/api/agent/framework/vercel-ai-sdk/create-agent.ts new file mode 100644 index 000000000..34b5ed7a7 --- /dev/null +++ b/typescript/create-onchain-agent/templates/next/app/api/agent/framework/vercel-ai-sdk/create-agent.ts @@ -0,0 +1,63 @@ +import { openai } from "@ai-sdk/openai"; +import { getVercelAITools } from "@coinbase/agentkit-vercel-ai-sdk"; +import { createReactAgent } from "@langchain/langgraph/prebuilt"; +import { prepareAgentkitAndWalletProvider } from "./prepare-agentkit"; + +// The agent +type Agent = { + tools: ReturnType, + system: string, + model: ReturnType, + maxSteps?: number, +} +let agent: Agent + +/** + * Initializes and returns an instance of the AI agent. + * If an agent instance already exists, it returns the existing one. + * + * @function getOrInitializeAgent + * @returns {Promise>} The initialized AI agent. + * + * @description Handles agent setup + * + * @throws {Error} If the agent initialization fails. + */ +export async function createAgent(): Promise { + // If agent has already been initialized, return it + if (agent) { + return agent; + } + + try { + const { agentkit, walletProvider } = await prepareAgentkitAndWalletProvider(); + + // Initialize Agent + const canUseFaucet = walletProvider.getNetwork().networkId == "base-sepolia"; + const faucetMessage = `If you ever need funds, you can request them from the faucet.`; + const cantUseFaucetMessage = `If you need funds, you can provide your wallet details and request funds from the user.`; + let system = ` + You are a helpful agent that can interact onchain using the Coinbase Developer Platform AgentKit. You are + empowered to interact onchain using your tools. ${canUseFaucet ? faucetMessage : cantUseFaucetMessage}. + Before executing your first action, get the wallet details to see what network + you're on. 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 CDP SDK + Agentkit, recommend they go to + docs.cdp.coinbase.com for more information. Be concise and helpful with your responses. Refrain from + restating your tools' descriptions unless it is explicitly requested. + ` + let tools = getVercelAITools(agentkit); + + agent = { + tools, + system, + model: openai("gpt-4o-mini"), + maxSteps: 10, + } + + return agent; + } catch (error) { + console.error("Error initializing agent:", error); + throw new Error("Failed to initialize agent"); + } +} \ No newline at end of file diff --git a/typescript/create-onchain-agent/templates/next/app/api/agent/framework/vercel-ai-sdk/prepare-agentkit.ts b/typescript/create-onchain-agent/templates/next/app/api/agent/framework/vercel-ai-sdk/prepare-agentkit.ts new file mode 100644 index 000000000..4ded11a39 --- /dev/null +++ b/typescript/create-onchain-agent/templates/next/app/api/agent/framework/vercel-ai-sdk/prepare-agentkit.ts @@ -0,0 +1,19 @@ +import { + AgentKit, + WalletProvider +} from "@coinbase/agentkit"; + +/** + * A stub function that throws a "Not implemented" error. + * + * This is a placeholder function for the implementation that is selected. + * The actual implementation is selected by the cli user that generated this framework. + * + * @function prepareAgentkitAndWalletProvider + * @returns {Promise<{ agentkit: AgentKit, walletProvider: WalletProvider }>} The initialized AI agent. + * + * @throws {Error} Throws a "Not implemented" error. + */ +export async function prepareAgentkitAndWalletProvider(): Promise<{ agentkit: AgentKit, walletProvider: WalletProvider }> { + throw new Error("Not implemented"); +} diff --git a/typescript/create-onchain-agent/templates/next/app/api/agent/framework/vercel-ai-sdk/route.ts b/typescript/create-onchain-agent/templates/next/app/api/agent/framework/vercel-ai-sdk/route.ts new file mode 100644 index 000000000..ed9ae54ca --- /dev/null +++ b/typescript/create-onchain-agent/templates/next/app/api/agent/framework/vercel-ai-sdk/route.ts @@ -0,0 +1,51 @@ +import { AgentRequest, AgentResponse } from "@/app/types/api"; +import { NextResponse } from "next/server"; +import { createAgent } from "./create-agent"; +import { Message, generateId, generateText} from "ai"; + +const messages: Message[] = []; + +/** + * Handles incoming POST requests to interact with the AgentKit-powered AI agent. + * This function processes user messages and streams responses from the agent. + * + * @function POST + * @param {Request & { json: () => Promise }} req - The incoming request object containing the user message. + * @returns {Promise>} JSON response containing the AI-generated reply or an error message. + * + * @description Sends a single message to the agent and returns the agents' final response. + * + * @example + * const response = await fetch("/api/agent", { + * method: "POST", + * headers: { "Content-Type": "application/json" }, + * body: JSON.stringify({ userMessage: input }), + * }); + */ +export async function POST( + req: Request & { json: () => Promise }, +): Promise> { + try { + // 1️. Extract user message from the request body + const { userMessage } = await req.json(); + + // 2. Get the agent + const agent = await createAgent(); + + // 3.Start streaming the agent's response + messages.push({ id: generateId(), role: "user", content: userMessage }); + const { text } = await generateText({ + ...agent, + messages, + }); + + // 4. Add the agent's response to the messages + messages.push({ id: generateId(), role: "assistant", content: text }); + + // 5️. Return the final response + return NextResponse.json({ response: text }); + } catch (error) { + console.error("Error processing request:", error); + return NextResponse.json({ error: "Failed to process message" }); + } +} diff --git a/typescript/create-onchain-agent/templates/next/app/api/agent/svm/privy/route.ts b/typescript/create-onchain-agent/templates/next/app/api/agent/svm/privy/route.ts deleted file mode 100644 index 462a3dade..000000000 --- a/typescript/create-onchain-agent/templates/next/app/api/agent/svm/privy/route.ts +++ /dev/null @@ -1,200 +0,0 @@ -import { AgentRequest, AgentResponse } from "@/app/types/api"; -import { - ActionProvider, - AgentKit, - cdpApiActionProvider, - jupiterActionProvider, - PrivyWalletConfig, - PrivyWalletProvider, - splActionProvider, - walletActionProvider, -} from "@coinbase/agentkit"; -import { getLangChainTools } from "@coinbase/agentkit-langchain"; -import { MemorySaver } from "@langchain/langgraph"; -import { createReactAgent } from "@langchain/langgraph/prebuilt"; -import { ChatOpenAI } from "@langchain/openai"; -import fs from "fs"; -import { NextResponse } from "next/server"; - -/** - * AgentKit Integration Route - * - * This file is your gateway to integrating AgentKit with your product. - * It defines the interaction between your system and the AI agent, - * allowing you to configure the agent to suit your needs. - * - * # Key Steps to Customize Your Agent:** - * - * 1. Select your LLM: - * - Modify the `ChatOpenAI` instantiation to choose your preferred LLM. - * - * 2. Set up your WalletProvider: - * - Learn more: https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#evm-wallet-providers - * - * 3️. Set up your ActionProviders: - * - ActionProviders define what your agent can do. - * - Choose from built-in providers or create your own: - * - Built-in: https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#action-providers - * - Custom: https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#creating-an-action-provider - * - * 4. Instantiate your Agent: - * - Pass the LLM, tools, and memory into `createReactAgent()` to bring your agent to life. - * - * # Next Steps: - * - Explore the AgentKit README: https://github.com/coinbase/agentkit - * - Learn more about available WalletProviders & ActionProviders. - * - Experiment with custom ActionProviders for your unique use case. - * - * ## Want to contribute? - * Join us in shaping AgentKit! Check out the contribution guide: - * - https://github.com/coinbase/agentkit/blob/main/CONTRIBUTING.md - * - https://discord.gg/CDP - */ - -// The agent -let agent: ReturnType; - -// Configure a file to persist the agent's Prviy Wallet Data -const WALLET_DATA_FILE = "wallet_data.txt"; - -/** - * Initializes and returns an instance of the AI agent. - * If an agent instance already exists, it returns the existing one. - * - * @function getOrInitializeAgent - * @returns {Promise>} The initialized AI agent. - * - * @description Handles agent setup - * - * @throws {Error} If the agent initialization fails. - */ -async function getOrInitializeAgent(): Promise> { - // If agent has already been initialized, return it - if (agent) { - return agent; - } - - try { - // Initialize LLM: https://platform.openai.com/docs/models#gpt-4o - const llm = new ChatOpenAI({ model: "gpt-4o-mini" }); - - // Initialize WalletProvider: https://docs.cdp.coinbase.com/agentkit/docs/wallet-management - const config: PrivyWalletConfig = { - appId: process.env.PRIVY_APP_ID as string, - appSecret: process.env.PRIVY_APP_SECRET as string, - walletId: process.env.PRIVY_WALLET_ID as string, - authorizationPrivateKey: process.env.PRIVY_WALLET_AUTHORIZATION_PRIVATE_KEY, - authorizationKeyId: process.env.PRIVY_WALLET_AUTHORIZATION_KEY_ID, - chainType: "solana", - networkId: process.env.NETWORK_ID, - }; - // Try to load saved wallet data - if (fs.existsSync(WALLET_DATA_FILE)) { - const savedWallet = JSON.parse(fs.readFileSync(WALLET_DATA_FILE, "utf8")); - config.walletId = savedWallet.walletId; - config.authorizationPrivateKey = savedWallet.authorizationPrivateKey; - config.networkId = savedWallet.networkId; - } - const walletProvider = await PrivyWalletProvider.configureWithWallet(config); - - // Initialize AgentKit: https://docs.cdp.coinbase.com/agentkit/docs/agent-actions - const actionProviders: ActionProvider[] = [ - walletActionProvider(), - splActionProvider(), - jupiterActionProvider(), - ]; - const canUseCdpApi = process.env.CDP_API_KEY_NAME && process.env.CDP_API_KEY_PRIVATE_KEY; - if (canUseCdpApi) { - actionProviders.push( - cdpApiActionProvider({ - apiKeyName: process.env.CDP_API_KEY_NAME, - apiKeyPrivateKey: process.env.CDP_API_KEY_PRIVATE_KEY, - }), - ); - } - const agentkit = await AgentKit.from({ - walletProvider, - actionProviders, - }); - const tools = await getLangChainTools(agentkit); - const memory = new MemorySaver(); - - // Initialize Agent - const canUseFaucet = walletProvider.getNetwork().networkId == "solana-devnet" && canUseCdpApi; - const faucetMessage = `If you ever need funds, you can request them from the faucet.`; - const cantUseFaucetMessage = `If you need funds, you can provide your wallet details and request funds from the user.`; - agent = createReactAgent({ - llm, - tools, - checkpointSaver: memory, - messageModifier: ` - You are a helpful agent that can interact onchain using the Coinbase Developer Platform AgentKit. You are - empowered to interact onchain using your tools. ${canUseFaucet ? faucetMessage : cantUseFaucetMessage}. - Before executing your first action, get the wallet details to see what network - you're on. 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 CDP SDK + Agentkit, recommend they go to - docs.cdp.coinbase.com for more information. Be concise and helpful with your responses. Refrain from - restating your tools' descriptions unless it is explicitly requested. - `, - }); - - // Save wallet data - const exportedWallet = walletProvider.exportWallet(); - fs.writeFileSync(WALLET_DATA_FILE, JSON.stringify(exportedWallet)); - - return agent; - } catch (error) { - console.error("Error initializing agent:", error); - throw new Error("Failed to initialize agent"); - } -} - -/** - * Handles incoming POST requests to interact with the AgentKit-powered AI agent. - * This function processes user messages and streams responses from the agent. - * - * @function POST - * @param {Request & { json: () => Promise }} req - The incoming request object containing the user message. - * @returns {Promise>} JSON response containing the AI-generated reply or an error message. - * - * @description Sends a single message to the agent and returns the agents' final response. - * - * @example - * const response = await fetch("/api/agent", { - * method: "POST", - * headers: { "Content-Type": "application/json" }, - * body: JSON.stringify({ userMessage: input }), - * }); - */ -export async function POST( - req: Request & { json: () => Promise }, -): Promise> { - try { - // 1️. Extract user message from the request body - const { userMessage } = await req.json(); - - // 2. Get the agent - const agent = await getOrInitializeAgent(); - - // 3.Start streaming the agent's response - const stream = await agent.stream( - { messages: [{ content: userMessage, role: "user" }] }, // The new message to send to the agent - { configurable: { thread_id: "AgentKit Discussion" } }, // Customizable thread ID for tracking conversations - ); - - // 4️. Process the streamed response chunks into a single message - let agentResponse = ""; - for await (const chunk of stream) { - if ("agent" in chunk) { - agentResponse += chunk.agent.messages[0].content; - } - } - - // 5️. Return the final response - return NextResponse.json({ response: agentResponse }); - } catch (error) { - console.error("Error processing request:", error); - return NextResponse.json({ error: "Failed to process message" }); - } -} diff --git a/typescript/create-onchain-agent/templates/next/app/api/agent/svm/solanaKeypair/route.ts b/typescript/create-onchain-agent/templates/next/app/api/agent/svm/solanaKeypair/route.ts deleted file mode 100644 index fd802a1d4..000000000 --- a/typescript/create-onchain-agent/templates/next/app/api/agent/svm/solanaKeypair/route.ts +++ /dev/null @@ -1,206 +0,0 @@ -import { AgentRequest, AgentResponse } from "@/app/types/api"; -import { - AgentKit, - SOLANA_NETWORK_ID, - SolanaKeypairWalletProvider, - splActionProvider, - walletActionProvider, - jupiterActionProvider, - cdpApiActionProvider, - ActionProvider, -} from "@coinbase/agentkit"; -import { getLangChainTools } from "@coinbase/agentkit-langchain"; -import { MemorySaver } from "@langchain/langgraph"; -import { createReactAgent } from "@langchain/langgraph/prebuilt"; -import { ChatOpenAI } from "@langchain/openai"; -import { Keypair } from "@solana/web3.js"; -import bs58 from "bs58"; -import { NextResponse } from "next/server"; -import fs from "fs"; -/** - * AgentKit Integration Route - * - * This file is your gateway to integrating AgentKit with your product. - * It defines the interaction between your system and the AI agent, - * allowing you to configure the agent to suit your needs. - * - * # Key Steps to Customize Your Agent:** - * - * 1. Select your LLM: - * - Modify the `ChatOpenAI` instantiation to choose your preferred LLM. - * - * 2. Set up your WalletProvider: - * - Learn more: https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#evm-wallet-providers - * - * 3️. Set up your ActionProviders: - * - ActionProviders define what your agent can do. - * - Choose from built-in providers or create your own: - * - Built-in: https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#action-providers - * - Custom: https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#creating-an-action-provider - * - * 4. Instantiate your Agent: - * - Pass the LLM, tools, and memory into `createReactAgent()` to bring your agent to life. - * - * # Next Steps: - * - Explore the AgentKit README: https://github.com/coinbase/agentkit - * - Learn more about available WalletProviders & ActionProviders. - * - Experiment with custom ActionProviders for your unique use case. - * - * ## Want to contribute? - * Join us in shaping AgentKit! Check out the contribution guide: - * - https://github.com/coinbase/agentkit/blob/main/CONTRIBUTING.md - * - https://discord.gg/CDP - */ - -// The agent -let agent: ReturnType; - -// Configure a file to persist a user's private key if none provided -const WALLET_DATA_FILE = "wallet_data.txt"; - -/** - * Initializes and returns an instance of the AI agent. - * If an agent instance already exists, it returns the existing one. - * - * @function getOrInitializeAgent - * @returns {Promise>} The initialized AI agent. - * - * @description Handles agent setup - * - * @throws {Error} If the agent initialization fails. - */ -async function getOrInitializeAgent(): Promise> { - // If agent has already been initialized, return it - if (agent) { - return agent; - } - - try { - // Initialize LLM: https://platform.openai.com/docs/models#gpt-4o - const llm = new ChatOpenAI({ model: "gpt-4o-mini" }); - - // Setup Private Key - let privateKey = process.env.SOLANA_PRIVATE_KEY as string; - if (!privateKey) { - if (fs.existsSync(WALLET_DATA_FILE)) { - privateKey = JSON.parse(fs.readFileSync(WALLET_DATA_FILE, "utf8")).privateKey; - console.info("Found private key in wallet_data.txt"); - } else { - const keypair = Keypair.generate(); - privateKey = bs58.encode(keypair.secretKey); - fs.writeFileSync(WALLET_DATA_FILE, JSON.stringify({ privateKey })); - console.log("Created new private key and saved to wallet_data.txt"); - console.log( - "We recommend you save this private key to your .env file and delete wallet_data.txt afterwards.", - ); - } - } - - // Initialize WalletProvider: https://docs.cdp.coinbase.com/agentkit/docs/wallet-management - // Configure Solana Keypair Wallet Provider - const rpcUrl = process.env.SOLANA_RPC_URL; - let walletProvider: SolanaKeypairWalletProvider; - if (rpcUrl) { - walletProvider = await SolanaKeypairWalletProvider.fromRpcUrl(rpcUrl, privateKey); - } else { - const network = (process.env.NETWORK_ID ?? "solana-devnet") as SOLANA_NETWORK_ID; - walletProvider = await SolanaKeypairWalletProvider.fromNetwork(network, privateKey); - } - - // Initialize AgentKit: https://docs.cdp.coinbase.com/agentkit/docs/agent-actions - const actionProviders: ActionProvider[] = [ - walletActionProvider(), - splActionProvider(), - jupiterActionProvider(), - ]; - const canUseCdpApi = process.env.CDP_API_KEY_NAME && process.env.CDP_API_KEY_PRIVATE_KEY; - if (canUseCdpApi) { - actionProviders.push( - cdpApiActionProvider({ - apiKeyName: process.env.CDP_API_KEY_NAME, - apiKeyPrivateKey: process.env.CDP_API_KEY_PRIVATE_KEY, - }), - ); - } - const agentkit = await AgentKit.from({ - walletProvider, - actionProviders, - }); - const tools = await getLangChainTools(agentkit); - const memory = new MemorySaver(); - - // Initialize Agent - const canUseFaucet = walletProvider.getNetwork().networkId == "solana-devnet" && canUseCdpApi; - const faucetMessage = `If you ever need funds, you can request them from the faucet.`; - const cantUseFaucetMessage = `If you need funds, you can provide your wallet details and request funds from the user.`; - agent = createReactAgent({ - llm, - tools, - checkpointSaver: memory, - messageModifier: ` - You are a helpful agent that can interact onchain using the Coinbase Developer Platform AgentKit. You are - empowered to interact onchain using your tools. ${canUseFaucet ? faucetMessage : cantUseFaucetMessage}. - Before executing your first action, get the wallet details to see what network - you're on. 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 CDP SDK + Agentkit, recommend they go to - docs.cdp.coinbase.com for more information. Be concise and helpful with your responses. Refrain from - restating your tools' descriptions unless it is explicitly requested. - `, - }); - - return agent; - } catch (error) { - console.error("Error initializing agent:", error); - throw new Error("Failed to initialize agent"); - } -} - -/** - * Handles incoming POST requests to interact with the AgentKit-powered AI agent. - * This function processes user messages and streams responses from the agent. - * - * @function POST - * @param {Request & { json: () => Promise }} req - The incoming request object containing the user message. - * @returns {Promise>} JSON response containing the AI-generated reply or an error message. - * - * @description Sends a single message to the agent and returns the agents' final response. - * - * @example - * const response = await fetch("/api/agent", { - * method: "POST", - * headers: { "Content-Type": "application/json" }, - * body: JSON.stringify({ userMessage: input }), - * }); - */ -export async function POST( - req: Request & { json: () => Promise }, -): Promise> { - try { - // 1️. Extract user message from the request body - const { userMessage } = await req.json(); - - // 2. Get the agent - const agent = await getOrInitializeAgent(); - - // 3.Start streaming the agent's response - const stream = await agent.stream( - { messages: [{ content: userMessage, role: "user" }] }, // The new message to send to the agent - { configurable: { thread_id: "AgentKit Discussion" } }, // Customizable thread ID for tracking conversations - ); - - // 4️. Process the streamed response chunks into a single message - let agentResponse = ""; - for await (const chunk of stream) { - if ("agent" in chunk) { - agentResponse += chunk.agent.messages[0].content; - } - } - - // 5️. Return the final response - return NextResponse.json({ response: agentResponse }); - } catch (error) { - console.error("Error processing request:", error); - return NextResponse.json({ error: "Failed to process message" }); - } -} diff --git a/typescript/create-onchain-agent/templates/next/package.json b/typescript/create-onchain-agent/templates/next/package.json index 766a993b8..424802922 100644 --- a/typescript/create-onchain-agent/templates/next/package.json +++ b/typescript/create-onchain-agent/templates/next/package.json @@ -9,13 +9,16 @@ "lint": "next lint" }, "dependencies": { + "@ai-sdk/openai": "^1.2.1", "@coinbase/agentkit": "^0.3.0", "@coinbase/agentkit-langchain": "^0.3.0", + "@coinbase/agentkit-vercel-ai-sdk": "^0.1.0", + "@langchain/core": "^0.3.19", "@langchain/langgraph": "^0.2.21", "@langchain/openai": "^0.3.14", - "@langchain/core": "^0.3.19", "@solana/web3.js": "^1.98.0", "@tanstack/react-query": "^5", + "ai": "^4.1.54", "bs58": "^6.0.0", "next": "14.2.15", "react": "^18", From dca4273001cb7200cbb269890f41abc9fbb416cd Mon Sep 17 00:00:00 2001 From: CarsonRoscoe Date: Tue, 11 Mar 2025 09:57:34 -0400 Subject: [PATCH 02/11] fix: handleNextSelection call --- typescript/create-onchain-agent/src/cli.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/typescript/create-onchain-agent/src/cli.ts b/typescript/create-onchain-agent/src/cli.ts index 86f6a2706..419702762 100644 --- a/typescript/create-onchain-agent/src/cli.ts +++ b/typescript/create-onchain-agent/src/cli.ts @@ -250,7 +250,7 @@ async function init() { // Handle selection-specific logic over copied-template switch (template) { case "next": - await handleNextSelection(root, walletProvider, network, chainId, rpcUrl, framework); + await handleNextSelection(root, framework, walletProvider, network, chainId, rpcUrl); spinner.succeed(); console.log(pc.blueBright(`\nSuccessfully created your AgentKit project in ${root}`)); From 747642de5109dce33323a63548c741eafd70577d Mon Sep 17 00:00:00 2001 From: CarsonRoscoe Date: Tue, 11 Mar 2025 10:02:38 -0400 Subject: [PATCH 03/11] chore: format and lint --- typescript/create-onchain-agent/src/cli.ts | 20 ++--- .../create-onchain-agent/src/constants.ts | 12 +-- .../create-onchain-agent/src/fileSystem.ts | 7 +- typescript/create-onchain-agent/src/types.ts | 2 +- typescript/create-onchain-agent/src/utils.ts | 16 ++-- .../custom-evm/viem/prepare-agentkit.ts | 23 ++--- .../agentkit/evm/cdp/prepare-agentkit.ts | 89 ++++++++++--------- .../agentkit/evm/privy/prepare-agentkit.ts | 7 +- .../agentkit/evm/smart/prepare-agentkit.ts | 5 +- .../agentkit/evm/viem/prepare-agentkit.ts | 7 +- .../agentkit/svm/privy/prepare-agentkit.ts | 5 +- .../svm/solanaKeypair/prepare-agentkit.ts | 5 +- .../agent/framework/langchain/create-agent.ts | 4 +- .../framework/langchain/prepare-agentkit.ts | 18 ++-- .../framework/vercel-ai-sdk/create-agent.ts | 22 ++--- .../vercel-ai-sdk/prepare-agentkit.ts | 18 ++-- .../agent/framework/vercel-ai-sdk/route.ts | 2 +- 17 files changed, 141 insertions(+), 121 deletions(-) diff --git a/typescript/create-onchain-agent/src/cli.ts b/typescript/create-onchain-agent/src/cli.ts index 419702762..12e886c43 100644 --- a/typescript/create-onchain-agent/src/cli.ts +++ b/typescript/create-onchain-agent/src/cli.ts @@ -5,7 +5,7 @@ import path from "path"; import pc from "picocolors"; import prompts from "prompts"; import { EVM_NETWORKS, NetworkToWalletProviders, SVM_NETWORKS } from "./constants.js"; -import { Network, WalletProviderChoice, Framework, Template } from "./types.js"; +import { Network, WalletProviderChoice, Framework } from "./types.js"; import { copyTemplate } from "./fileSystem.js"; import { handleNextSelection, @@ -89,11 +89,11 @@ async function init() { })), }, { - type: (prev, { framework }) => + type: (prev, { framework }) => FrameworkToTemplates[framework as Framework].length > 1 ? "select" : null, name: "template", message: pc.reset("Choose a template:"), - choices: (prev, { framework }) => + choices: (prev, { framework }) => FrameworkToTemplates[framework as Framework].map(template => ({ title: template, value: template, @@ -230,13 +230,7 @@ async function init() { } process.exit(1); } - const { - projectName, - network, - chainId, - rpcUrl, - framework - } = result; + const { projectName, network, chainId, rpcUrl, framework } = result; const packageName = result.packageName || toValidPackageName(projectName); const walletProvider = result.walletProvider || "Viem"; // If template wasn't selected (because there was only one option), use the first template @@ -254,7 +248,7 @@ async function init() { spinner.succeed(); console.log(pc.blueBright(`\nSuccessfully created your AgentKit project in ${root}`)); - + console.log(`\nFrameworks:`); console.log(pc.gray("- AgentKit")); console.log(pc.gray(`- ${framework}`)); @@ -262,9 +256,9 @@ async function init() { console.log(pc.gray("- Next.js")); console.log(pc.gray("- Tailwind CSS")); console.log(pc.gray("- ESLint")); - + console.log(pc.bold("\nWhat's Next?")); - + console.log(`\nTo get started, run the following commands:\n`); if (root !== process.cwd()) { console.log(` - cd ${path.relative(process.cwd(), root)}`); diff --git a/typescript/create-onchain-agent/src/constants.ts b/typescript/create-onchain-agent/src/constants.ts index 80bd27704..52feaa0e5 100644 --- a/typescript/create-onchain-agent/src/constants.ts +++ b/typescript/create-onchain-agent/src/constants.ts @@ -162,18 +162,20 @@ export const Frameworks: Framework[] = ["Langchain", "Vercel AI SDK", "Model Con export const Templates: Template[] = ["next", "mcpServer"]; export const FrameworkToTemplates: Record = { - "Langchain": ["next"], + Langchain: ["next"], "Vercel AI SDK": ["next"], "Model Context Protocol": ["mcpServer"], }; export type NextTemplateRouteConfiguration = { - createAgentRoute: `${string}.ts`, - apiRoute: `${string}.ts`, + createAgentRoute: `${string}.ts`; + apiRoute: `${string}.ts`; }; -export const NextTemplateRouteConfigurations: Partial> = { - "Langchain": { +export const NextTemplateRouteConfigurations: Partial< + Record +> = { + Langchain: { apiRoute: "langchain/route.ts", createAgentRoute: "langchain/create-agent.ts", }, diff --git a/typescript/create-onchain-agent/src/fileSystem.ts b/typescript/create-onchain-agent/src/fileSystem.ts index 2ad87252e..c4e54432a 100644 --- a/typescript/create-onchain-agent/src/fileSystem.ts +++ b/typescript/create-onchain-agent/src/fileSystem.ts @@ -17,6 +17,7 @@ const excludeFiles = [".DS_Store", "Thumbs.db"]; /** * Retrieves the source directory for copying template files. * + * @param template - The template to use. * @returns {string} The source directory path. */ function getSourceDir(template: Template): string { @@ -66,7 +67,11 @@ async function copyDir(src: string, dest: string): Promise { * @param {Template} template - The template to use. * @returns {Promise} The path of the newly created project directory. */ -export async function copyTemplate(projectName: string, packageName: string, template: Template): Promise { +export async function copyTemplate( + projectName: string, + packageName: string, + template: Template, +): Promise { const root = path.join(process.cwd(), projectName); await copyDir(getSourceDir(template), root); diff --git a/typescript/create-onchain-agent/src/types.ts b/typescript/create-onchain-agent/src/types.ts index ceaf95d3a..05e70a323 100644 --- a/typescript/create-onchain-agent/src/types.ts +++ b/typescript/create-onchain-agent/src/types.ts @@ -35,4 +35,4 @@ export type NetworkSelection = { export type Framework = "Langchain" | "Vercel AI SDK" | "Model Context Protocol"; -export type Template = 'next' | 'mcpServer'; \ No newline at end of file +export type Template = "next" | "mcpServer"; diff --git a/typescript/create-onchain-agent/src/utils.ts b/typescript/create-onchain-agent/src/utils.ts index d34635da3..423157722 100644 --- a/typescript/create-onchain-agent/src/utils.ts +++ b/typescript/create-onchain-agent/src/utils.ts @@ -177,7 +177,7 @@ export const getWalletProviders = (network?: Network): WalletProviderChoice[] => * - Deletes all unselected API routes and cleans up empty directories. * * @param {string} root - The root directory of the project. - * @param {Framework} framework - The selected framework. + * @param {Framework} framework - The selected framework. * @param {WalletProviderChoice} walletProvider - The selected wallet provider. * @param {Network} [network] - The optional blockchain network. * @param {string} [chainId] - The optional chain ID for the network. @@ -242,15 +242,13 @@ export async function handleNextSelection( const selectedRoutePath = path.join(agentDir, type, toPromose); const newRoutePath = path.join(agentDir, to); await fs.rename(selectedRoutePath, newRoutePath); - } + }; - await promoteRoute(agentkitRouteConfig.prepareAgentkitRoute, 'agentkit', "prepare-agentkit.ts"); - await promoteRoute(frameworkRouteConfig.createAgentRoute, 'framework', "create-agent.ts"); - await promoteRoute(frameworkRouteConfig.apiRoute, 'framework', "route.ts"); + await promoteRoute(agentkitRouteConfig.prepareAgentkitRoute, "agentkit", "prepare-agentkit.ts"); + await promoteRoute(frameworkRouteConfig.createAgentRoute, "framework", "create-agent.ts"); + await promoteRoute(frameworkRouteConfig.apiRoute, "framework", "route.ts"); // Delete boilerplate routes - await fs.rm(path.join(agentDir, 'agentkit'), { recursive: true, force: true }); - await fs.rm(path.join(agentDir, 'framework'), { recursive: true, force: true }); + await fs.rm(path.join(agentDir, "agentkit"), { recursive: true, force: true }); + await fs.rm(path.join(agentDir, "framework"), { recursive: true, force: true }); } - - diff --git a/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/custom-evm/viem/prepare-agentkit.ts b/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/custom-evm/viem/prepare-agentkit.ts index 08c5e5159..05eb808f1 100644 --- a/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/custom-evm/viem/prepare-agentkit.ts +++ b/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/custom-evm/viem/prepare-agentkit.ts @@ -52,16 +52,19 @@ import { generatePrivateKey, privateKeyToAccount } from "viem/accounts"; const WALLET_DATA_FILE = "wallet_data.txt"; /** -* Prepares the AgentKit and WalletProvider. -* -* @function prepareAgentkitAndWalletProvider -* @returns {Promise<{ agentkit: AgentKit, walletProvider: WalletProvider }>} The initialized AI agent. -* -* @description Handles agent setup -* -* @throws {Error} If the agent initialization fails. -*/ -export async function prepareAgentkitAndWalletProvider(): Promise<{ agentkit: AgentKit, walletProvider: WalletProvider }> { + * Prepares the AgentKit and WalletProvider. + * + * @function prepareAgentkitAndWalletProvider + * @returns {Promise<{ agentkit: AgentKit, walletProvider: WalletProvider }>} The initialized AI agent. + * + * @description Handles agent setup + * + * @throws {Error} If the agent initialization fails. + */ +export async function prepareAgentkitAndWalletProvider(): Promise<{ + agentkit: AgentKit; + walletProvider: WalletProvider; +}> { try { // Initialize WalletProvider: https://docs.cdp.coinbase.com/agentkit/docs/wallet-management let privateKey = process.env.PRIVATE_KEY as `0x${string}`; diff --git a/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/evm/cdp/prepare-agentkit.ts b/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/evm/cdp/prepare-agentkit.ts index 5a2caf3aa..177d82990 100644 --- a/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/evm/cdp/prepare-agentkit.ts +++ b/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/evm/cdp/prepare-agentkit.ts @@ -12,54 +12,57 @@ import { import * as fs from "fs"; /** -* AgentKit Integration Route -* -* This file is your gateway to integrating AgentKit with your product. -* It defines the interaction between your system and the AI agent, -* allowing you to configure the agent to suit your needs. -* -* # Key Steps to Customize Your Agent:** -* -* 1. Select your LLM: -* - Modify the `ChatOpenAI` instantiation to choose your preferred LLM. -* -* 2. Set up your WalletProvider: -* - Learn more: https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#evm-wallet-providers -* -* 3️. Set up your ActionProviders: -* - ActionProviders define what your agent can do. -* - Choose from built-in providers or create your own: -* - Built-in: https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#action-providers -* - Custom: https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#creating-an-action-provider -* -* 4. Instantiate your Agent: -* - Pass the LLM, tools, and memory into `createReactAgent()` to bring your agent to life. -* -* # Next Steps: -* - Explore the AgentKit README: https://github.com/coinbase/agentkit -* - Learn more about available WalletProviders & ActionProviders. -* - Experiment with custom ActionProviders for your unique use case. -* -* ## Want to contribute? -* Join us in shaping AgentKit! Check out the contribution guide: -* - https://github.com/coinbase/agentkit/blob/main/CONTRIBUTING.md -* - https://discord.gg/CDP -*/ + * AgentKit Integration Route + * + * This file is your gateway to integrating AgentKit with your product. + * It defines the interaction between your system and the AI agent, + * allowing you to configure the agent to suit your needs. + * + * # Key Steps to Customize Your Agent:** + * + * 1. Select your LLM: + * - Modify the `ChatOpenAI` instantiation to choose your preferred LLM. + * + * 2. Set up your WalletProvider: + * - Learn more: https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#evm-wallet-providers + * + * 3️. Set up your ActionProviders: + * - ActionProviders define what your agent can do. + * - Choose from built-in providers or create your own: + * - Built-in: https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#action-providers + * - Custom: https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#creating-an-action-provider + * + * 4. Instantiate your Agent: + * - Pass the LLM, tools, and memory into `createReactAgent()` to bring your agent to life. + * + * # Next Steps: + * - Explore the AgentKit README: https://github.com/coinbase/agentkit + * - Learn more about available WalletProviders & ActionProviders. + * - Experiment with custom ActionProviders for your unique use case. + * + * ## Want to contribute? + * Join us in shaping AgentKit! Check out the contribution guide: + * - https://github.com/coinbase/agentkit/blob/main/CONTRIBUTING.md + * - https://discord.gg/CDP + */ // Configure a file to persist the agent's CDP MPC Wallet Data const WALLET_DATA_FILE = "wallet_data.txt"; /** -* Prepares the AgentKit and WalletProvider. -* -* @function prepareAgentkitAndWalletProvider -* @returns {Promise<{ agentkit: AgentKit, walletProvider: WalletProvider }>} The initialized AI agent. -* -* @description Handles agent setup -* -* @throws {Error} If the agent initialization fails. -*/ -export async function prepareAgentkitAndWalletProvider(): Promise<{ agentkit: AgentKit, walletProvider: WalletProvider }> { + * Prepares the AgentKit and WalletProvider. + * + * @function prepareAgentkitAndWalletProvider + * @returns {Promise<{ agentkit: AgentKit, walletProvider: WalletProvider }>} The initialized AI agent. + * + * @description Handles agent setup + * + * @throws {Error} If the agent initialization fails. + */ +export async function prepareAgentkitAndWalletProvider(): Promise<{ + agentkit: AgentKit; + walletProvider: WalletProvider; +}> { try { let walletDataStr: string | null = null; diff --git a/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/evm/privy/prepare-agentkit.ts b/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/evm/privy/prepare-agentkit.ts index 2120b1f70..ba9cab5c2 100644 --- a/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/evm/privy/prepare-agentkit.ts +++ b/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/evm/privy/prepare-agentkit.ts @@ -60,7 +60,10 @@ const WALLET_DATA_FILE = "wallet_data.txt"; * * @throws {Error} If the agent initialization fails. */ -export async function prepareAgentkitAndWalletProvider(): Promise<{ agentkit: AgentKit, walletProvider: WalletProvider }> { +export async function prepareAgentkitAndWalletProvider(): Promise<{ + agentkit: AgentKit; + walletProvider: WalletProvider; +}> { try { // Initialize WalletProvider: https://docs.cdp.coinbase.com/agentkit/docs/wallet-management const config: PrivyWalletConfig = { @@ -108,7 +111,7 @@ export async function prepareAgentkitAndWalletProvider(): Promise<{ agentkit: Ag walletProvider, actionProviders, }); - + // Save wallet data const exportedWallet = walletProvider.exportWallet(); fs.writeFileSync(WALLET_DATA_FILE, JSON.stringify(exportedWallet)); diff --git a/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/evm/smart/prepare-agentkit.ts b/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/evm/smart/prepare-agentkit.ts index 3579b23c5..7abe4302e 100644 --- a/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/evm/smart/prepare-agentkit.ts +++ b/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/evm/smart/prepare-agentkit.ts @@ -66,7 +66,10 @@ type WalletData = { * * @throws {Error} If the agent initialization fails. */ -export async function prepareAgentkitAndWalletProvider(): Promise<{ agentkit: AgentKit, walletProvider: WalletProvider }> { +export async function prepareAgentkitAndWalletProvider(): Promise<{ + agentkit: AgentKit; + walletProvider: WalletProvider; +}> { try { let walletData: WalletData | null = null; let privateKey: Hex | null = null; diff --git a/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/evm/viem/prepare-agentkit.ts b/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/evm/viem/prepare-agentkit.ts index a78ad1a7d..94446b2e2 100644 --- a/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/evm/viem/prepare-agentkit.ts +++ b/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/evm/viem/prepare-agentkit.ts @@ -62,7 +62,10 @@ const WALLET_DATA_FILE = "wallet_data.txt"; * * @throws {Error} If the agent initialization fails. */ -export async function prepareAgentkitAndWalletProvider(): Promise<{ agentkit: AgentKit, walletProvider: WalletProvider }> { +export async function prepareAgentkitAndWalletProvider(): Promise<{ + agentkit: AgentKit; + walletProvider: WalletProvider; +}> { try { // Initialize WalletProvider: https://docs.cdp.coinbase.com/agentkit/docs/wallet-management let privateKey = process.env.PRIVATE_KEY as Hex; @@ -110,7 +113,7 @@ export async function prepareAgentkitAndWalletProvider(): Promise<{ agentkit: Ag walletProvider, actionProviders, }); - + return { agentkit, walletProvider }; } catch (error) { console.error("Error initializing agent:", error); diff --git a/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/svm/privy/prepare-agentkit.ts b/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/svm/privy/prepare-agentkit.ts index c0af16477..dd8a76442 100644 --- a/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/svm/privy/prepare-agentkit.ts +++ b/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/svm/privy/prepare-agentkit.ts @@ -59,7 +59,10 @@ const WALLET_DATA_FILE = "wallet_data.txt"; * * @throws {Error} If the agent initialization fails. */ -export async function prepareAgentkitAndWalletProvider(): Promise<{ agentkit: AgentKit, walletProvider: WalletProvider }> { +export async function prepareAgentkitAndWalletProvider(): Promise<{ + agentkit: AgentKit; + walletProvider: WalletProvider; +}> { try { // Initialize WalletProvider: https://docs.cdp.coinbase.com/agentkit/docs/wallet-management const config: PrivyWalletConfig = { diff --git a/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/svm/solanaKeypair/prepare-agentkit.ts b/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/svm/solanaKeypair/prepare-agentkit.ts index a97a92f0f..416a078d0 100644 --- a/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/svm/solanaKeypair/prepare-agentkit.ts +++ b/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/svm/solanaKeypair/prepare-agentkit.ts @@ -60,7 +60,10 @@ const WALLET_DATA_FILE = "wallet_data.txt"; * * @throws {Error} If the agent initialization fails. */ -export async function prepareAgentkitAndWalletProvider(): Promise<{ agentkit: AgentKit, walletProvider: WalletProvider }> { +export async function prepareAgentkitAndWalletProvider(): Promise<{ + agentkit: AgentKit; + walletProvider: WalletProvider; +}> { try { // Setup Private Key let privateKey = process.env.SOLANA_PRIVATE_KEY as string; diff --git a/typescript/create-onchain-agent/templates/next/app/api/agent/framework/langchain/create-agent.ts b/typescript/create-onchain-agent/templates/next/app/api/agent/framework/langchain/create-agent.ts index 3edbdd5b9..42b12ee06 100644 --- a/typescript/create-onchain-agent/templates/next/app/api/agent/framework/langchain/create-agent.ts +++ b/typescript/create-onchain-agent/templates/next/app/api/agent/framework/langchain/create-agent.ts @@ -10,7 +10,7 @@ let agent: ReturnType; /** * Initializes and returns an instance of the AI agent. * If an agent instance already exists, it returns the existing one. - * + * * @function getOrInitializeAgent * @returns {Promise>} The initialized AI agent. * @@ -58,4 +58,4 @@ export async function createAgent(): Promise console.error("Error initializing agent:", error); throw new Error("Failed to initialize agent"); } -} \ No newline at end of file +} diff --git a/typescript/create-onchain-agent/templates/next/app/api/agent/framework/langchain/prepare-agentkit.ts b/typescript/create-onchain-agent/templates/next/app/api/agent/framework/langchain/prepare-agentkit.ts index 4ded11a39..07f33cf57 100644 --- a/typescript/create-onchain-agent/templates/next/app/api/agent/framework/langchain/prepare-agentkit.ts +++ b/typescript/create-onchain-agent/templates/next/app/api/agent/framework/langchain/prepare-agentkit.ts @@ -1,19 +1,19 @@ -import { - AgentKit, - WalletProvider -} from "@coinbase/agentkit"; +import { AgentKit, WalletProvider } from "@coinbase/agentkit"; /** * A stub function that throws a "Not implemented" error. - * - * This is a placeholder function for the implementation that is selected. - * The actual implementation is selected by the cli user that generated this framework. - * + * + * This is a placeholder function for the implementation that is selected. + * The actual implementation is selected by the cli user that generated this framework. + * * @function prepareAgentkitAndWalletProvider * @returns {Promise<{ agentkit: AgentKit, walletProvider: WalletProvider }>} The initialized AI agent. * * @throws {Error} Throws a "Not implemented" error. */ -export async function prepareAgentkitAndWalletProvider(): Promise<{ agentkit: AgentKit, walletProvider: WalletProvider }> { +export async function prepareAgentkitAndWalletProvider(): Promise<{ + agentkit: AgentKit; + walletProvider: WalletProvider; +}> { throw new Error("Not implemented"); } diff --git a/typescript/create-onchain-agent/templates/next/app/api/agent/framework/vercel-ai-sdk/create-agent.ts b/typescript/create-onchain-agent/templates/next/app/api/agent/framework/vercel-ai-sdk/create-agent.ts index 34b5ed7a7..3eaa57dfb 100644 --- a/typescript/create-onchain-agent/templates/next/app/api/agent/framework/vercel-ai-sdk/create-agent.ts +++ b/typescript/create-onchain-agent/templates/next/app/api/agent/framework/vercel-ai-sdk/create-agent.ts @@ -5,17 +5,17 @@ import { prepareAgentkitAndWalletProvider } from "./prepare-agentkit"; // The agent type Agent = { - tools: ReturnType, - system: string, - model: ReturnType, - maxSteps?: number, -} -let agent: Agent + tools: ReturnType; + system: string; + model: ReturnType; + maxSteps?: number; +}; +let agent: Agent; /** * Initializes and returns an instance of the AI agent. * If an agent instance already exists, it returns the existing one. - * + * * @function getOrInitializeAgent * @returns {Promise>} The initialized AI agent. * @@ -45,19 +45,19 @@ export async function createAgent(): Promise { encourage them to implement it themselves using the CDP SDK + Agentkit, recommend they go to docs.cdp.coinbase.com for more information. Be concise and helpful with your responses. Refrain from restating your tools' descriptions unless it is explicitly requested. - ` - let tools = getVercelAITools(agentkit); + `; + let tools = getVercelAITools(agentkit); agent = { tools, system, model: openai("gpt-4o-mini"), maxSteps: 10, - } + }; return agent; } catch (error) { console.error("Error initializing agent:", error); throw new Error("Failed to initialize agent"); } -} \ No newline at end of file +} diff --git a/typescript/create-onchain-agent/templates/next/app/api/agent/framework/vercel-ai-sdk/prepare-agentkit.ts b/typescript/create-onchain-agent/templates/next/app/api/agent/framework/vercel-ai-sdk/prepare-agentkit.ts index 4ded11a39..07f33cf57 100644 --- a/typescript/create-onchain-agent/templates/next/app/api/agent/framework/vercel-ai-sdk/prepare-agentkit.ts +++ b/typescript/create-onchain-agent/templates/next/app/api/agent/framework/vercel-ai-sdk/prepare-agentkit.ts @@ -1,19 +1,19 @@ -import { - AgentKit, - WalletProvider -} from "@coinbase/agentkit"; +import { AgentKit, WalletProvider } from "@coinbase/agentkit"; /** * A stub function that throws a "Not implemented" error. - * - * This is a placeholder function for the implementation that is selected. - * The actual implementation is selected by the cli user that generated this framework. - * + * + * This is a placeholder function for the implementation that is selected. + * The actual implementation is selected by the cli user that generated this framework. + * * @function prepareAgentkitAndWalletProvider * @returns {Promise<{ agentkit: AgentKit, walletProvider: WalletProvider }>} The initialized AI agent. * * @throws {Error} Throws a "Not implemented" error. */ -export async function prepareAgentkitAndWalletProvider(): Promise<{ agentkit: AgentKit, walletProvider: WalletProvider }> { +export async function prepareAgentkitAndWalletProvider(): Promise<{ + agentkit: AgentKit; + walletProvider: WalletProvider; +}> { throw new Error("Not implemented"); } diff --git a/typescript/create-onchain-agent/templates/next/app/api/agent/framework/vercel-ai-sdk/route.ts b/typescript/create-onchain-agent/templates/next/app/api/agent/framework/vercel-ai-sdk/route.ts index ed9ae54ca..3cd2872de 100644 --- a/typescript/create-onchain-agent/templates/next/app/api/agent/framework/vercel-ai-sdk/route.ts +++ b/typescript/create-onchain-agent/templates/next/app/api/agent/framework/vercel-ai-sdk/route.ts @@ -1,7 +1,7 @@ import { AgentRequest, AgentResponse } from "@/app/types/api"; import { NextResponse } from "next/server"; import { createAgent } from "./create-agent"; -import { Message, generateId, generateText} from "ai"; +import { Message, generateId, generateText } from "ai"; const messages: Message[] = []; From d57c0c77d56fa590ffef5fe79c2b839c3699e449 Mon Sep 17 00:00:00 2001 From: CarsonRoscoe Date: Tue, 11 Mar 2025 10:11:14 -0400 Subject: [PATCH 04/11] chore: updated comments --- .../custom-evm/viem/prepare-agentkit.ts | 26 +++++++----------- .../agentkit/evm/cdp/prepare-agentkit.ts | 26 +++++++----------- .../agentkit/evm/privy/prepare-agentkit.ts | 26 +++++++----------- .../agentkit/evm/smart/prepare-agentkit.ts | 26 +++++++----------- .../agentkit/evm/viem/prepare-agentkit.ts | 26 +++++++----------- .../agentkit/svm/privy/prepare-agentkit.ts | 26 +++++++----------- .../svm/solanaKeypair/prepare-agentkit.ts | 27 ++++++++----------- .../agent/framework/langchain/create-agent.ts | 16 +++++++++++ .../framework/vercel-ai-sdk/create-agent.ts | 22 +++++++++++++-- 9 files changed, 107 insertions(+), 114 deletions(-) diff --git a/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/custom-evm/viem/prepare-agentkit.ts b/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/custom-evm/viem/prepare-agentkit.ts index 05eb808f1..cede3ead2 100644 --- a/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/custom-evm/viem/prepare-agentkit.ts +++ b/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/custom-evm/viem/prepare-agentkit.ts @@ -17,30 +17,24 @@ import { generatePrivateKey, privateKeyToAccount } from "viem/accounts"; * AgentKit Integration Route * * This file is your gateway to integrating AgentKit with your product. - * It defines the interaction between your system and the AI agent, - * allowing you to configure the agent to suit your needs. + * It defines the core capabilities of your agent through WalletProvider + * and ActionProvider configuration. * - * # Key Steps to Customize Your Agent:** - * - * 1. Select your LLM: - * - Modify the `ChatOpenAI` instantiation to choose your preferred LLM. - * - * 2. Set up your WalletProvider: + * Key Components: + * 1. WalletProvider Setup: + * - Configures the blockchain wallet integration * - Learn more: https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#evm-wallet-providers * - * 3️. Set up your ActionProviders: - * - ActionProviders define what your agent can do. - * - Choose from built-in providers or create your own: + * 2. ActionProviders Setup: + * - Defines the specific actions your agent can perform + * - Choose from built-in providers or create custom ones: * - Built-in: https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#action-providers * - Custom: https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#creating-an-action-provider * - * 4. Instantiate your Agent: - * - Pass the LLM, tools, and memory into `createReactAgent()` to bring your agent to life. - * * # Next Steps: * - Explore the AgentKit README: https://github.com/coinbase/agentkit - * - Learn more about available WalletProviders & ActionProviders. - * - Experiment with custom ActionProviders for your unique use case. + * - Experiment with different LLM configurations + * - Fine-tune agent parameters for your use case * * ## Want to contribute? * Join us in shaping AgentKit! Check out the contribution guide: diff --git a/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/evm/cdp/prepare-agentkit.ts b/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/evm/cdp/prepare-agentkit.ts index 177d82990..b0fca2bce 100644 --- a/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/evm/cdp/prepare-agentkit.ts +++ b/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/evm/cdp/prepare-agentkit.ts @@ -15,30 +15,24 @@ import * as fs from "fs"; * AgentKit Integration Route * * This file is your gateway to integrating AgentKit with your product. - * It defines the interaction between your system and the AI agent, - * allowing you to configure the agent to suit your needs. + * It defines the core capabilities of your agent through WalletProvider + * and ActionProvider configuration. * - * # Key Steps to Customize Your Agent:** - * - * 1. Select your LLM: - * - Modify the `ChatOpenAI` instantiation to choose your preferred LLM. - * - * 2. Set up your WalletProvider: + * Key Components: + * 1. WalletProvider Setup: + * - Configures the blockchain wallet integration * - Learn more: https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#evm-wallet-providers * - * 3️. Set up your ActionProviders: - * - ActionProviders define what your agent can do. - * - Choose from built-in providers or create your own: + * 2. ActionProviders Setup: + * - Defines the specific actions your agent can perform + * - Choose from built-in providers or create custom ones: * - Built-in: https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#action-providers * - Custom: https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#creating-an-action-provider * - * 4. Instantiate your Agent: - * - Pass the LLM, tools, and memory into `createReactAgent()` to bring your agent to life. - * * # Next Steps: * - Explore the AgentKit README: https://github.com/coinbase/agentkit - * - Learn more about available WalletProviders & ActionProviders. - * - Experiment with custom ActionProviders for your unique use case. + * - Experiment with different LLM configurations + * - Fine-tune agent parameters for your use case * * ## Want to contribute? * Join us in shaping AgentKit! Check out the contribution guide: diff --git a/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/evm/privy/prepare-agentkit.ts b/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/evm/privy/prepare-agentkit.ts index ba9cab5c2..aac839956 100644 --- a/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/evm/privy/prepare-agentkit.ts +++ b/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/evm/privy/prepare-agentkit.ts @@ -16,30 +16,24 @@ import fs from "fs"; * AgentKit Integration Route * * This file is your gateway to integrating AgentKit with your product. - * It defines the interaction between your system and the AI agent, - * allowing you to configure the agent to suit your needs. + * It defines the core capabilities of your agent through WalletProvider + * and ActionProvider configuration. * - * # Key Steps to Customize Your Agent:** - * - * 1. Select your LLM: - * - Modify the `ChatOpenAI` instantiation to choose your preferred LLM. - * - * 2. Set up your WalletProvider: + * Key Components: + * 1. WalletProvider Setup: + * - Configures the blockchain wallet integration * - Learn more: https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#evm-wallet-providers * - * 3️. Set up your ActionProviders: - * - ActionProviders define what your agent can do. - * - Choose from built-in providers or create your own: + * 2. ActionProviders Setup: + * - Defines the specific actions your agent can perform + * - Choose from built-in providers or create custom ones: * - Built-in: https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#action-providers * - Custom: https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#creating-an-action-provider * - * 4. Instantiate your Agent: - * - Pass the LLM, tools, and memory into `createReactAgent()` to bring your agent to life. - * * # Next Steps: * - Explore the AgentKit README: https://github.com/coinbase/agentkit - * - Learn more about available WalletProviders & ActionProviders. - * - Experiment with custom ActionProviders for your unique use case. + * - Experiment with different LLM configurations + * - Fine-tune agent parameters for your use case * * ## Want to contribute? * Join us in shaping AgentKit! Check out the contribution guide: diff --git a/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/evm/smart/prepare-agentkit.ts b/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/evm/smart/prepare-agentkit.ts index 7abe4302e..e872ac6f8 100644 --- a/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/evm/smart/prepare-agentkit.ts +++ b/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/evm/smart/prepare-agentkit.ts @@ -17,30 +17,24 @@ import { generatePrivateKey, privateKeyToAccount } from "viem/accounts"; * AgentKit Integration Route * * This file is your gateway to integrating AgentKit with your product. - * It defines the interaction between your system and the AI agent, - * allowing you to configure the agent to suit your needs. + * It defines the core capabilities of your agent through WalletProvider + * and ActionProvider configuration. * - * # Key Steps to Customize Your Agent:** - * - * 1. Select your LLM: - * - Modify the `ChatOpenAI` instantiation to choose your preferred LLM. - * - * 2. Set up your WalletProvider: + * Key Components: + * 1. WalletProvider Setup: + * - Configures the blockchain wallet integration * - Learn more: https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#evm-wallet-providers * - * 3️. Set up your ActionProviders: - * - ActionProviders define what your agent can do. - * - Choose from built-in providers or create your own: + * 2. ActionProviders Setup: + * - Defines the specific actions your agent can perform + * - Choose from built-in providers or create custom ones: * - Built-in: https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#action-providers * - Custom: https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#creating-an-action-provider * - * 4. Instantiate your Agent: - * - Pass the LLM, tools, and memory into `createReactAgent()` to bring your agent to life. - * * # Next Steps: * - Explore the AgentKit README: https://github.com/coinbase/agentkit - * - Learn more about available WalletProviders & ActionProviders. - * - Experiment with custom ActionProviders for your unique use case. + * - Experiment with different LLM configurations + * - Fine-tune agent parameters for your use case * * ## Want to contribute? * Join us in shaping AgentKit! Check out the contribution guide: diff --git a/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/evm/viem/prepare-agentkit.ts b/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/evm/viem/prepare-agentkit.ts index 94446b2e2..83a3af09c 100644 --- a/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/evm/viem/prepare-agentkit.ts +++ b/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/evm/viem/prepare-agentkit.ts @@ -18,30 +18,24 @@ import { generatePrivateKey, privateKeyToAccount } from "viem/accounts"; * AgentKit Integration Route * * This file is your gateway to integrating AgentKit with your product. - * It defines the interaction between your system and the AI agent, - * allowing you to configure the agent to suit your needs. + * It defines the core capabilities of your agent through WalletProvider + * and ActionProvider configuration. * - * # Key Steps to Customize Your Agent:** - * - * 1. Select your LLM: - * - Modify the `ChatOpenAI` instantiation to choose your preferred LLM. - * - * 2. Set up your WalletProvider: + * Key Components: + * 1. WalletProvider Setup: + * - Configures the blockchain wallet integration * - Learn more: https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#evm-wallet-providers * - * 3️. Set up your ActionProviders: - * - ActionProviders define what your agent can do. - * - Choose from built-in providers or create your own: + * 2. ActionProviders Setup: + * - Defines the specific actions your agent can perform + * - Choose from built-in providers or create custom ones: * - Built-in: https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#action-providers * - Custom: https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#creating-an-action-provider * - * 4. Instantiate your Agent: - * - Pass the LLM, tools, and memory into `createReactAgent()` to bring your agent to life. - * * # Next Steps: * - Explore the AgentKit README: https://github.com/coinbase/agentkit - * - Learn more about available WalletProviders & ActionProviders. - * - Experiment with custom ActionProviders for your unique use case. + * - Experiment with different LLM configurations + * - Fine-tune agent parameters for your use case * * ## Want to contribute? * Join us in shaping AgentKit! Check out the contribution guide: diff --git a/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/svm/privy/prepare-agentkit.ts b/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/svm/privy/prepare-agentkit.ts index dd8a76442..eb304fbac 100644 --- a/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/svm/privy/prepare-agentkit.ts +++ b/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/svm/privy/prepare-agentkit.ts @@ -15,30 +15,24 @@ import fs from "fs"; * AgentKit Integration Route * * This file is your gateway to integrating AgentKit with your product. - * It defines the interaction between your system and the AI agent, - * allowing you to configure the agent to suit your needs. + * It defines the core capabilities of your agent through WalletProvider + * and ActionProvider configuration. * - * # Key Steps to Customize Your Agent:** - * - * 1. Select your LLM: - * - Modify the `ChatOpenAI` instantiation to choose your preferred LLM. - * - * 2. Set up your WalletProvider: + * Key Components: + * 1. WalletProvider Setup: + * - Configures the blockchain wallet integration * - Learn more: https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#evm-wallet-providers * - * 3️. Set up your ActionProviders: - * - ActionProviders define what your agent can do. - * - Choose from built-in providers or create your own: + * 2. ActionProviders Setup: + * - Defines the specific actions your agent can perform + * - Choose from built-in providers or create custom ones: * - Built-in: https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#action-providers * - Custom: https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#creating-an-action-provider * - * 4. Instantiate your Agent: - * - Pass the LLM, tools, and memory into `createReactAgent()` to bring your agent to life. - * * # Next Steps: * - Explore the AgentKit README: https://github.com/coinbase/agentkit - * - Learn more about available WalletProviders & ActionProviders. - * - Experiment with custom ActionProviders for your unique use case. + * - Experiment with different LLM configurations + * - Fine-tune agent parameters for your use case * * ## Want to contribute? * Join us in shaping AgentKit! Check out the contribution guide: diff --git a/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/svm/solanaKeypair/prepare-agentkit.ts b/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/svm/solanaKeypair/prepare-agentkit.ts index 416a078d0..05f12f62e 100644 --- a/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/svm/solanaKeypair/prepare-agentkit.ts +++ b/typescript/create-onchain-agent/templates/next/app/api/agent/agentkit/svm/solanaKeypair/prepare-agentkit.ts @@ -12,34 +12,29 @@ import { import { Keypair } from "@solana/web3.js"; import bs58 from "bs58"; import fs from "fs"; + /** * AgentKit Integration Route * * This file is your gateway to integrating AgentKit with your product. - * It defines the interaction between your system and the AI agent, - * allowing you to configure the agent to suit your needs. - * - * # Key Steps to Customize Your Agent:** + * It defines the core capabilities of your agent through WalletProvider + * and ActionProvider configuration. * - * 1. Select your LLM: - * - Modify the `ChatOpenAI` instantiation to choose your preferred LLM. - * - * 2. Set up your WalletProvider: + * Key Components: + * 1. WalletProvider Setup: + * - Configures the blockchain wallet integration * - Learn more: https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#evm-wallet-providers * - * 3️. Set up your ActionProviders: - * - ActionProviders define what your agent can do. - * - Choose from built-in providers or create your own: + * 2. ActionProviders Setup: + * - Defines the specific actions your agent can perform + * - Choose from built-in providers or create custom ones: * - Built-in: https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#action-providers * - Custom: https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#creating-an-action-provider * - * 4. Instantiate your Agent: - * - Pass the LLM, tools, and memory into `createReactAgent()` to bring your agent to life. - * * # Next Steps: * - Explore the AgentKit README: https://github.com/coinbase/agentkit - * - Learn more about available WalletProviders & ActionProviders. - * - Experiment with custom ActionProviders for your unique use case. + * - Experiment with different LLM configurations + * - Fine-tune agent parameters for your use case * * ## Want to contribute? * Join us in shaping AgentKit! Check out the contribution guide: diff --git a/typescript/create-onchain-agent/templates/next/app/api/agent/framework/langchain/create-agent.ts b/typescript/create-onchain-agent/templates/next/app/api/agent/framework/langchain/create-agent.ts index 42b12ee06..96c82f549 100644 --- a/typescript/create-onchain-agent/templates/next/app/api/agent/framework/langchain/create-agent.ts +++ b/typescript/create-onchain-agent/templates/next/app/api/agent/framework/langchain/create-agent.ts @@ -4,6 +4,22 @@ import { createReactAgent } from "@langchain/langgraph/prebuilt"; import { ChatOpenAI } from "@langchain/openai"; import { prepareAgentkitAndWalletProvider } from "./prepare-agentkit"; +/** + * Agent Configuration Guide + * + * This file handles the core configuration of your AI agent's behavior and capabilities. + * + * Key Steps to Customize Your Agent: + * + * 1. Select your LLM: + * - Modify the `ChatOpenAI` instantiation to choose your preferred LLM + * - Configure model parameters like temperature and max tokens + * + * 2. Instantiate your Agent: + * - Pass the LLM, tools, and memory into `createReactAgent()` + * - Configure agent-specific parameters + */ + // The agent let agent: ReturnType; diff --git a/typescript/create-onchain-agent/templates/next/app/api/agent/framework/vercel-ai-sdk/create-agent.ts b/typescript/create-onchain-agent/templates/next/app/api/agent/framework/vercel-ai-sdk/create-agent.ts index 3eaa57dfb..485963258 100644 --- a/typescript/create-onchain-agent/templates/next/app/api/agent/framework/vercel-ai-sdk/create-agent.ts +++ b/typescript/create-onchain-agent/templates/next/app/api/agent/framework/vercel-ai-sdk/create-agent.ts @@ -1,8 +1,23 @@ import { openai } from "@ai-sdk/openai"; import { getVercelAITools } from "@coinbase/agentkit-vercel-ai-sdk"; -import { createReactAgent } from "@langchain/langgraph/prebuilt"; import { prepareAgentkitAndWalletProvider } from "./prepare-agentkit"; +/** + * Agent Configuration Guide + * + * This file handles the core configuration of your AI agent's behavior and capabilities. + * + * Key Steps to Customize Your Agent: + * + * 1. Select your LLM: + * - Modify the `openai` instantiation to choose your preferred LLM + * - Configure model parameters like temperature and max tokens + * + * 2. Instantiate your Agent: + * - Pass the LLM, tools, and memory into `createReactAgent()` + * - Configure agent-specific parameters + */ + // The agent type Agent = { tools: ReturnType; @@ -30,6 +45,9 @@ export async function createAgent(): Promise { } try { + // Initialize LLM: https://platform.openai.com/docs/models#gpt-4o + const model = openai("gpt-4o-mini"); + const { agentkit, walletProvider } = await prepareAgentkitAndWalletProvider(); // Initialize Agent @@ -51,7 +69,7 @@ export async function createAgent(): Promise { agent = { tools, system, - model: openai("gpt-4o-mini"), + model, maxSteps: 10, }; From eb35eaafd34c7c247f1ff7038ce9cad6104dd1fa Mon Sep 17 00:00:00 2001 From: CarsonRoscoe Date: Tue, 11 Mar 2025 10:12:07 -0400 Subject: [PATCH 05/11] chore: changelog --- typescript/.changeset/slick-points-smile.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 typescript/.changeset/slick-points-smile.md diff --git a/typescript/.changeset/slick-points-smile.md b/typescript/.changeset/slick-points-smile.md new file mode 100644 index 000000000..391e05bd4 --- /dev/null +++ b/typescript/.changeset/slick-points-smile.md @@ -0,0 +1,5 @@ +--- +"create-onchain-agent": patch +--- + +Added multi framework support From 0f451bf1c25b57dd72809129437dae235a1af5b0 Mon Sep 17 00:00:00 2001 From: CarsonRoscoe Date: Tue, 11 Mar 2025 10:15:58 -0400 Subject: [PATCH 06/11] chore: updated readmes --- typescript/create-onchain-agent/README.md | 8 +++++--- typescript/create-onchain-agent/templates/next/README.md | 4 ++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/typescript/create-onchain-agent/README.md b/typescript/create-onchain-agent/README.md index 4c38e5ee3..ec8d5781f 100644 --- a/typescript/create-onchain-agent/README.md +++ b/typescript/create-onchain-agent/README.md @@ -24,6 +24,7 @@ This command will guide you through setting up an onchain agent project by promp ## Features - **Guided setup**: Interactive prompts help configure the project. +- **Supports multiple AI frameworks**. - **Supports multiple blockchain networks**. - **Select your preferred wallet provider**. - **Preconfigured with Next.js, React, Tailwind CSS, and ESLint**. @@ -34,9 +35,10 @@ The CLI will prompt you for the following details: 1. **Project Name**: The name of your new onchain agent project. 2. **Package Name**: The npm package name (auto-formatted if needed). -3. **Network**: Choose from available blockchain networks. -4. **Chain ID**: Specify if using a custom network. -5. **Wallet Provider**: Select a preferred method for wallet management. +3. **Framework**: Choose from available AI frameworks. +4. **Network**: Choose from available blockchain networks. +5. **Chain ID**: Specify if using a custom network. +6. **Wallet Provider**: Select a preferred method for wallet management. After answering the prompts, the CLI will: diff --git a/typescript/create-onchain-agent/templates/next/README.md b/typescript/create-onchain-agent/templates/next/README.md index 33be04f06..10e498c48 100644 --- a/typescript/create-onchain-agent/templates/next/README.md +++ b/typescript/create-onchain-agent/templates/next/README.md @@ -29,10 +29,10 @@ Open [http://localhost:3000](http://localhost:3000) in your browser to see the p ## Configuring Your Agent -You can [modify your configuration](https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#usage) of the agent. By default, your agent configuration occurs in the `/api/agent/route.ts` file. +You can [modify your configuration](https://github.com/coinbase/agentkit/tree/main/typescript/agentkit#usage) of the agent. By default, your agentkit configuration occurs in the `/api/agent/prepare-agentkit.ts` file, and agent instantiation occurs in the `/api/agent/create-agent.ts` file. ### 1. Select Your LLM -Modify the `ChatOpenAI` instantiation to use the model of your choice. +Modify the OpenAI model instantiation to use the model of your choice. ### 2. Select Your Wallet Provider AgentKit requires a **Wallet Provider** to interact with blockchain networks. From 110a87da4a016a83a49bf75a86ed6dd6df2c696d Mon Sep 17 00:00:00 2001 From: CarsonRoscoe Date: Tue, 11 Mar 2025 10:16:47 -0400 Subject: [PATCH 07/11] chore: added todo and removed MCP from Framework list for now --- typescript/create-onchain-agent/src/constants.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/typescript/create-onchain-agent/src/constants.ts b/typescript/create-onchain-agent/src/constants.ts index 52feaa0e5..213ac2449 100644 --- a/typescript/create-onchain-agent/src/constants.ts +++ b/typescript/create-onchain-agent/src/constants.ts @@ -157,7 +157,7 @@ export const AgentkitRouteConfigurations: Record< }, }; -export const Frameworks: Framework[] = ["Langchain", "Vercel AI SDK", "Model Context Protocol"]; +export const Frameworks: Framework[] = ["Langchain", "Vercel AI SDK"]; // TODO: Add "Model Context Protocol" once the "mcpServer" template is added export const Templates: Template[] = ["next", "mcpServer"]; From 874653ed6fb794e52709e89d7c785c52455b5fb5 Mon Sep 17 00:00:00 2001 From: CarsonRoscoe Date: Tue, 11 Mar 2025 17:18:24 -0400 Subject: [PATCH 08/11] chore: removed references to mcpServer and MCP. Will readd in its own PR --- typescript/create-onchain-agent/src/constants.ts | 5 ++--- typescript/create-onchain-agent/src/types.ts | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/typescript/create-onchain-agent/src/constants.ts b/typescript/create-onchain-agent/src/constants.ts index 213ac2449..7ebab6606 100644 --- a/typescript/create-onchain-agent/src/constants.ts +++ b/typescript/create-onchain-agent/src/constants.ts @@ -157,14 +157,13 @@ export const AgentkitRouteConfigurations: Record< }, }; -export const Frameworks: Framework[] = ["Langchain", "Vercel AI SDK"]; // TODO: Add "Model Context Protocol" once the "mcpServer" template is added +export const Frameworks: Framework[] = ["Langchain", "Vercel AI SDK"]; -export const Templates: Template[] = ["next", "mcpServer"]; +export const Templates: Template[] = ["next"]; export const FrameworkToTemplates: Record = { Langchain: ["next"], "Vercel AI SDK": ["next"], - "Model Context Protocol": ["mcpServer"], }; export type NextTemplateRouteConfiguration = { diff --git a/typescript/create-onchain-agent/src/types.ts b/typescript/create-onchain-agent/src/types.ts index 05e70a323..e6e77919c 100644 --- a/typescript/create-onchain-agent/src/types.ts +++ b/typescript/create-onchain-agent/src/types.ts @@ -33,6 +33,6 @@ export type NetworkSelection = { rpcUrl?: string; }; -export type Framework = "Langchain" | "Vercel AI SDK" | "Model Context Protocol"; +export type Framework = "Langchain" | "Vercel AI SDK"; -export type Template = "next" | "mcpServer"; +export type Template = "next"; From 20e9abae2d2e789ace3adbbf0c3b80192229bf7a Mon Sep 17 00:00:00 2001 From: CarsonRoscoe Date: Tue, 11 Mar 2025 17:26:59 -0400 Subject: [PATCH 09/11] chore: updated package-lock --- typescript/package-lock.json | 152 +++++++++++++++++------------------ 1 file changed, 74 insertions(+), 78 deletions(-) diff --git a/typescript/package-lock.json b/typescript/package-lock.json index 23aa3700a..db1ee6e0f 100644 --- a/typescript/package-lock.json +++ b/typescript/package-lock.json @@ -286,13 +286,16 @@ "name": "next-template", "version": "0.1.0", "dependencies": { + "@ai-sdk/openai": "^1.2.1", "@coinbase/agentkit": "^0.3.0", "@coinbase/agentkit-langchain": "^0.3.0", + "@coinbase/agentkit-vercel-ai-sdk": "^0.1.0", "@langchain/core": "^0.3.19", "@langchain/langgraph": "^0.2.21", "@langchain/openai": "^0.3.14", "@solana/web3.js": "^1.98.0", "@tanstack/react-query": "^5", + "ai": "^4.1.54", "bs58": "^6.0.0", "next": "14.2.15", "react": "^18", @@ -560,13 +563,12 @@ "license": "MIT" }, "node_modules/@ai-sdk/openai": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ai-sdk/openai/-/openai-1.2.0.tgz", - "integrity": "sha512-tzxH6OxKL5ffts4zJPdziQSJGGpSrQcJmuSrE92jCt7pJ4PAU5Dx4tjNNFIU8lSfwarLnywejZEt3Fz0uQZZOQ==", - "license": "Apache-2.0", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@ai-sdk/openai/-/openai-1.2.2.tgz", + "integrity": "sha512-5355FLtSOH8sz9N9fsSwWpTaEgfqKOPMMHgSs1j4Aih5kQc9PhJ/oAPZuH308c/ktrbx6GcCW/hVrITimYsQhQ==", "dependencies": { - "@ai-sdk/provider": "1.0.9", - "@ai-sdk/provider-utils": "2.1.10" + "@ai-sdk/provider": "1.0.10", + "@ai-sdk/provider-utils": "2.1.11" }, "engines": { "node": ">=18" @@ -576,10 +578,9 @@ } }, "node_modules/@ai-sdk/provider": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@ai-sdk/provider/-/provider-1.0.9.tgz", - "integrity": "sha512-jie6ZJT2ZR0uVOVCDc9R2xCX5I/Dum/wEK28lx21PJx6ZnFAN9EzD2WsPhcDWfCgGx3OAZZ0GyM3CEobXpa9LA==", - "license": "Apache-2.0", + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider/-/provider-1.0.10.tgz", + "integrity": "sha512-pco8Zl9U0xwXI+nCLc0woMtxbvjU8hRmGTseAUiPHFLYAAL8trRPCukg69IDeinOvIeo1SmXxAIdWWPZOLb4Cg==", "dependencies": { "json-schema": "^0.4.0" }, @@ -588,12 +589,11 @@ } }, "node_modules/@ai-sdk/provider-utils": { - "version": "2.1.10", - "resolved": "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-2.1.10.tgz", - "integrity": "sha512-4GZ8GHjOFxePFzkl3q42AU0DQOtTQ5w09vmaWUf/pKFXJPizlnzKSUkF0f+VkapIUfDugyMqPMT1ge8XQzVI7Q==", - "license": "Apache-2.0", + "version": "2.1.11", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-2.1.11.tgz", + "integrity": "sha512-lMnXA5KaRJidzW7gQmlo/SnX6D+AKk5GxHFcQtOaGOSJNmu/qcNZc1rGaO7K5qW52OvCLXtnWudR4cc/FvMpVQ==", "dependencies": { - "@ai-sdk/provider": "1.0.9", + "@ai-sdk/provider": "1.0.10", "eventsource-parser": "^3.0.0", "nanoid": "^3.3.8", "secure-json-parse": "^2.7.0" @@ -611,13 +611,12 @@ } }, "node_modules/@ai-sdk/react": { - "version": "1.1.20", - "resolved": "https://registry.npmjs.org/@ai-sdk/react/-/react-1.1.20.tgz", - "integrity": "sha512-4QOM9fR9SryaRraybckDjrhl1O6XejqELdKmrM5g9y9eLnWAfjwF+W1aN0knkSHzbbjMqN77sy9B9yL8EuJbDw==", - "license": "Apache-2.0", + "version": "1.1.21", + "resolved": "https://registry.npmjs.org/@ai-sdk/react/-/react-1.1.21.tgz", + "integrity": "sha512-VKgqzG5wKjyLhROiFhRdyMuDcGu5QPfdLU5J7ovqR1HecknxymL3nCXsxWbAaiZ0khm2EsST6L6zwUbriZrKgg==", "dependencies": { - "@ai-sdk/provider-utils": "2.1.10", - "@ai-sdk/ui-utils": "1.1.16", + "@ai-sdk/provider-utils": "2.1.11", + "@ai-sdk/ui-utils": "1.1.17", "swr": "^2.2.5", "throttleit": "2.1.0" }, @@ -638,13 +637,12 @@ } }, "node_modules/@ai-sdk/ui-utils": { - "version": "1.1.16", - "resolved": "https://registry.npmjs.org/@ai-sdk/ui-utils/-/ui-utils-1.1.16.tgz", - "integrity": "sha512-jfblR2yZVISmNK2zyNzJZFtkgX57WDAUQXcmn3XUBJyo8LFsADu+/vYMn5AOyBi9qJT0RBk11PEtIxIqvByw3Q==", - "license": "Apache-2.0", + "version": "1.1.17", + "resolved": "https://registry.npmjs.org/@ai-sdk/ui-utils/-/ui-utils-1.1.17.tgz", + "integrity": "sha512-fCnp/wntZGqPf6tiCmhuQoSDLSBhXoI5DU2JX4As96EO870+jliE6ozvYUwYOZC6Ta2OKAjjWPcSP7HeHX0b+g==", "dependencies": { - "@ai-sdk/provider": "1.0.9", - "@ai-sdk/provider-utils": "2.1.10", + "@ai-sdk/provider": "1.0.10", + "@ai-sdk/provider-utils": "2.1.11", "zod-to-json-schema": "^3.24.1" }, "engines": { @@ -5894,15 +5892,14 @@ } }, "node_modules/ai": { - "version": "4.1.50", - "resolved": "https://registry.npmjs.org/ai/-/ai-4.1.50.tgz", - "integrity": "sha512-YBNeemrJKDrxoBQd3V9aaxhKm5q5YyRcF7PZE7W0NmLuvsdva/1aQNYTAsxs47gQFdvqfYmlFy4B0E+356OlPA==", - "license": "Apache-2.0", - "dependencies": { - "@ai-sdk/provider": "1.0.9", - "@ai-sdk/provider-utils": "2.1.10", - "@ai-sdk/react": "1.1.20", - "@ai-sdk/ui-utils": "1.1.16", + "version": "4.1.54", + "resolved": "https://registry.npmjs.org/ai/-/ai-4.1.54.tgz", + "integrity": "sha512-VcUZhNEC9i1OpdhDaz1cF0IllgMqhwoUdqHQT1U3dKvS9KnOa9qvEtUUAilA+VHI/1LSZF4VzGhXPC7QMT9NMg==", + "dependencies": { + "@ai-sdk/provider": "1.0.10", + "@ai-sdk/provider-utils": "2.1.11", + "@ai-sdk/react": "1.1.21", + "@ai-sdk/ui-utils": "1.1.17", "@opentelemetry/api": "1.9.0", "jsondiffpatch": "0.6.0" }, @@ -12278,8 +12275,7 @@ "node_modules/json-schema": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", - "license": "(AFL-2.1 OR BSD-3-Clause)" + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" }, "node_modules/json-schema-traverse": { "version": "0.4.1", @@ -16441,8 +16437,7 @@ "node_modules/secure-json-parse": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-2.7.0.tgz", - "integrity": "sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==", - "license": "BSD-3-Clause" + "integrity": "sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==" }, "node_modules/semver": { "version": "7.7.0", @@ -17407,10 +17402,9 @@ "license": "MIT" }, "node_modules/swr": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/swr/-/swr-2.3.2.tgz", - "integrity": "sha512-RosxFpiabojs75IwQ316DGoDRmOqtiAj0tg8wCcbEu4CiLZBs/a9QNtHV7TUfDXmmlgqij/NqzKq/eLelyv9xA==", - "license": "MIT", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/swr/-/swr-2.3.3.tgz", + "integrity": "sha512-dshNvs3ExOqtZ6kJBaAsabhPdHyeY4P2cKwRCniDVifBMoG/SVI7tfLWqPXriVspf2Rg4tPzXJTnwaihIeFw2A==", "dependencies": { "dequal": "^2.0.3", "use-sync-external-store": "^1.4.0" @@ -17586,7 +17580,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-2.1.0.tgz", "integrity": "sha512-nt6AMGKW1p/70DF/hGBdJB57B8Tspmbp5gfJ8ilhLnt7kkr2ye7hzD6NVG8GGErk2HWF34igrL2CXmNIkzKqKw==", - "license": "MIT", "engines": { "node": ">=18" }, @@ -19312,51 +19305,51 @@ "integrity": "sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw==" }, "@ai-sdk/openai": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ai-sdk/openai/-/openai-1.2.0.tgz", - "integrity": "sha512-tzxH6OxKL5ffts4zJPdziQSJGGpSrQcJmuSrE92jCt7pJ4PAU5Dx4tjNNFIU8lSfwarLnywejZEt3Fz0uQZZOQ==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@ai-sdk/openai/-/openai-1.2.2.tgz", + "integrity": "sha512-5355FLtSOH8sz9N9fsSwWpTaEgfqKOPMMHgSs1j4Aih5kQc9PhJ/oAPZuH308c/ktrbx6GcCW/hVrITimYsQhQ==", "requires": { - "@ai-sdk/provider": "1.0.9", - "@ai-sdk/provider-utils": "2.1.10" + "@ai-sdk/provider": "1.0.10", + "@ai-sdk/provider-utils": "2.1.11" } }, "@ai-sdk/provider": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@ai-sdk/provider/-/provider-1.0.9.tgz", - "integrity": "sha512-jie6ZJT2ZR0uVOVCDc9R2xCX5I/Dum/wEK28lx21PJx6ZnFAN9EzD2WsPhcDWfCgGx3OAZZ0GyM3CEobXpa9LA==", + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider/-/provider-1.0.10.tgz", + "integrity": "sha512-pco8Zl9U0xwXI+nCLc0woMtxbvjU8hRmGTseAUiPHFLYAAL8trRPCukg69IDeinOvIeo1SmXxAIdWWPZOLb4Cg==", "requires": { "json-schema": "^0.4.0" } }, "@ai-sdk/provider-utils": { - "version": "2.1.10", - "resolved": "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-2.1.10.tgz", - "integrity": "sha512-4GZ8GHjOFxePFzkl3q42AU0DQOtTQ5w09vmaWUf/pKFXJPizlnzKSUkF0f+VkapIUfDugyMqPMT1ge8XQzVI7Q==", + "version": "2.1.11", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-2.1.11.tgz", + "integrity": "sha512-lMnXA5KaRJidzW7gQmlo/SnX6D+AKk5GxHFcQtOaGOSJNmu/qcNZc1rGaO7K5qW52OvCLXtnWudR4cc/FvMpVQ==", "requires": { - "@ai-sdk/provider": "1.0.9", + "@ai-sdk/provider": "1.0.10", "eventsource-parser": "^3.0.0", "nanoid": "^3.3.8", "secure-json-parse": "^2.7.0" } }, "@ai-sdk/react": { - "version": "1.1.20", - "resolved": "https://registry.npmjs.org/@ai-sdk/react/-/react-1.1.20.tgz", - "integrity": "sha512-4QOM9fR9SryaRraybckDjrhl1O6XejqELdKmrM5g9y9eLnWAfjwF+W1aN0knkSHzbbjMqN77sy9B9yL8EuJbDw==", + "version": "1.1.21", + "resolved": "https://registry.npmjs.org/@ai-sdk/react/-/react-1.1.21.tgz", + "integrity": "sha512-VKgqzG5wKjyLhROiFhRdyMuDcGu5QPfdLU5J7ovqR1HecknxymL3nCXsxWbAaiZ0khm2EsST6L6zwUbriZrKgg==", "requires": { - "@ai-sdk/provider-utils": "2.1.10", - "@ai-sdk/ui-utils": "1.1.16", + "@ai-sdk/provider-utils": "2.1.11", + "@ai-sdk/ui-utils": "1.1.17", "swr": "^2.2.5", "throttleit": "2.1.0" } }, "@ai-sdk/ui-utils": { - "version": "1.1.16", - "resolved": "https://registry.npmjs.org/@ai-sdk/ui-utils/-/ui-utils-1.1.16.tgz", - "integrity": "sha512-jfblR2yZVISmNK2zyNzJZFtkgX57WDAUQXcmn3XUBJyo8LFsADu+/vYMn5AOyBi9qJT0RBk11PEtIxIqvByw3Q==", + "version": "1.1.17", + "resolved": "https://registry.npmjs.org/@ai-sdk/ui-utils/-/ui-utils-1.1.17.tgz", + "integrity": "sha512-fCnp/wntZGqPf6tiCmhuQoSDLSBhXoI5DU2JX4As96EO870+jliE6ozvYUwYOZC6Ta2OKAjjWPcSP7HeHX0b+g==", "requires": { - "@ai-sdk/provider": "1.0.9", - "@ai-sdk/provider-utils": "2.1.10", + "@ai-sdk/provider": "1.0.10", + "@ai-sdk/provider-utils": "2.1.11", "zod-to-json-schema": "^3.24.1" } }, @@ -23306,14 +23299,14 @@ } }, "ai": { - "version": "4.1.50", - "resolved": "https://registry.npmjs.org/ai/-/ai-4.1.50.tgz", - "integrity": "sha512-YBNeemrJKDrxoBQd3V9aaxhKm5q5YyRcF7PZE7W0NmLuvsdva/1aQNYTAsxs47gQFdvqfYmlFy4B0E+356OlPA==", - "requires": { - "@ai-sdk/provider": "1.0.9", - "@ai-sdk/provider-utils": "2.1.10", - "@ai-sdk/react": "1.1.20", - "@ai-sdk/ui-utils": "1.1.16", + "version": "4.1.54", + "resolved": "https://registry.npmjs.org/ai/-/ai-4.1.54.tgz", + "integrity": "sha512-VcUZhNEC9i1OpdhDaz1cF0IllgMqhwoUdqHQT1U3dKvS9KnOa9qvEtUUAilA+VHI/1LSZF4VzGhXPC7QMT9NMg==", + "requires": { + "@ai-sdk/provider": "1.0.10", + "@ai-sdk/provider-utils": "2.1.11", + "@ai-sdk/react": "1.1.21", + "@ai-sdk/ui-utils": "1.1.17", "@opentelemetry/api": "1.9.0", "jsondiffpatch": "0.6.0" } @@ -28797,8 +28790,10 @@ "next-template": { "version": "file:create-onchain-agent/templates/next", "requires": { + "@ai-sdk/openai": "^1.2.1", "@coinbase/agentkit": "^0.3.0", "@coinbase/agentkit-langchain": "^0.3.0", + "@coinbase/agentkit-vercel-ai-sdk": "^0.1.0", "@langchain/core": "^0.3.19", "@langchain/langgraph": "^0.2.21", "@langchain/openai": "^0.3.14", @@ -28807,6 +28802,7 @@ "@types/node": "^20", "@types/react": "^18", "@types/react-dom": "^18", + "ai": "^4.1.54", "bs58": "^6.0.0", "eslint": "^8", "eslint-config-next": "14.2.15", @@ -31247,9 +31243,9 @@ } }, "swr": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/swr/-/swr-2.3.2.tgz", - "integrity": "sha512-RosxFpiabojs75IwQ316DGoDRmOqtiAj0tg8wCcbEu4CiLZBs/a9QNtHV7TUfDXmmlgqij/NqzKq/eLelyv9xA==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/swr/-/swr-2.3.3.tgz", + "integrity": "sha512-dshNvs3ExOqtZ6kJBaAsabhPdHyeY4P2cKwRCniDVifBMoG/SVI7tfLWqPXriVspf2Rg4tPzXJTnwaihIeFw2A==", "requires": { "dequal": "^2.0.3", "use-sync-external-store": "^1.4.0" From 92e6a0d008661f2f7e26efdfcc872c299512824c Mon Sep 17 00:00:00 2001 From: CarsonRoscoe Date: Tue, 11 Mar 2025 17:28:29 -0400 Subject: [PATCH 10/11] chore: removed missed mcpServer reference --- typescript/create-onchain-agent/src/cli.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/typescript/create-onchain-agent/src/cli.ts b/typescript/create-onchain-agent/src/cli.ts index 12e886c43..5abf9c591 100644 --- a/typescript/create-onchain-agent/src/cli.ts +++ b/typescript/create-onchain-agent/src/cli.ts @@ -268,8 +268,7 @@ async function init() { console.log(" - mv .env.local .env"); console.log(" - npm run dev"); break; - case "mcpServer": - // TODO: Implement MCP Server template + default: break; } From 42b47d7ec5b28d4885b3feda44fa9764fddbb6a4 Mon Sep 17 00:00:00 2001 From: CarsonRoscoe Date: Tue, 11 Mar 2025 17:30:57 -0400 Subject: [PATCH 11/11] chore: lint --- .../app/api/agent/framework/vercel-ai-sdk/create-agent.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/typescript/create-onchain-agent/templates/next/app/api/agent/framework/vercel-ai-sdk/create-agent.ts b/typescript/create-onchain-agent/templates/next/app/api/agent/framework/vercel-ai-sdk/create-agent.ts index 485963258..7814813c4 100644 --- a/typescript/create-onchain-agent/templates/next/app/api/agent/framework/vercel-ai-sdk/create-agent.ts +++ b/typescript/create-onchain-agent/templates/next/app/api/agent/framework/vercel-ai-sdk/create-agent.ts @@ -54,7 +54,7 @@ export async function createAgent(): Promise { const canUseFaucet = walletProvider.getNetwork().networkId == "base-sepolia"; const faucetMessage = `If you ever need funds, you can request them from the faucet.`; const cantUseFaucetMessage = `If you need funds, you can provide your wallet details and request funds from the user.`; - let system = ` + const system = ` You are a helpful agent that can interact onchain using the Coinbase Developer Platform AgentKit. You are empowered to interact onchain using your tools. ${canUseFaucet ? faucetMessage : cantUseFaucetMessage}. Before executing your first action, get the wallet details to see what network @@ -64,7 +64,7 @@ export async function createAgent(): Promise { docs.cdp.coinbase.com for more information. Be concise and helpful with your responses. Refrain from restating your tools' descriptions unless it is explicitly requested. `; - let tools = getVercelAITools(agentkit); + const tools = getVercelAITools(agentkit); agent = { tools,