Skip to content

Commit 229430c

Browse files
Add tutorial for creating an AI agent with the SDK (#1993)
* Add tutorial for creating an AI agent with the SDK * Update what's new * address reviewer feedback
1 parent 0d927b4 commit 229430c

9 files changed

+346
-0
lines changed

docs/whats-new.md

+2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ of the [MetaMask developer page](https://metamask.io/developer/).
1515

1616
## April 2025
1717

18+
- Added a tutorial for [creating a wallet AI agent with the SDK](/sdk/tutorials/create-wallet-ai-agent).
19+
([#1993](https://github.com/MetaMask/metamask-docs/pull/1993))
1820
- Documented [Ethereum Hoodi testnet](/services/get-started/endpoints/#ethereum) support. ([#1977](https://github.com/MetaMask/metamask-docs/pull/1977))
1921
- Documented [how to use deeplinks](/sdk/guides/use-deeplinks).
2022
([#1928](https://github.com/MetaMask/metamask-docs/pull/1928))

docusaurus.config.js

+12
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,18 @@ const config = {
357357
prism: {
358358
theme: codeTheme,
359359
additionalLanguages: ['csharp', 'gradle', 'bash', 'json'],
360+
magicComments: [
361+
{
362+
className: "git-diff-remove",
363+
line: "remove-next-line",
364+
block: { start: "remove-start", end: "remove-end" },
365+
},
366+
{
367+
className: "git-diff-add",
368+
line: "add-next-line",
369+
block: { start: "add-start", end: "add-end" },
370+
},
371+
],
360372
},
361373
algolia: {
362374
// The application ID provided by Algolia

sdk-sidebar.js

+7
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,13 @@ const sidebar = {
5656
},
5757
],
5858
},
59+
{
60+
type:'category',
61+
label: 'Tutorials',
62+
collapsible: false,
63+
collapsed: false,
64+
items: ['tutorials/create-wallet-ai-agent'],
65+
},
5966
{
6067
type: 'category',
6168
label: 'Reference',
54.2 KB
Loading
75.6 KB
Loading

sdk/_assets/sdk-ai-agent-txn-sent.png

83.2 KB
Loading

sdk/_assets/sdk-ai-agent.png

48.8 KB
Loading
+309
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,309 @@
1+
---
2+
description: Create a wallet AI agent using MetaMask SDK and Vercel's AI SDK.
3+
---
4+
5+
import Tabs from "@theme/Tabs";
6+
import TabItem from "@theme/TabItem";
7+
8+
# Create a wallet AI agent
9+
10+
This tutorial walks you through creating an AI agent dapp that can display your wallet balance and initiate transactions from your wallet, on the Linea Sepolia network.
11+
You will use a provided template, which sets up MetaMask SDK and [Vercel's AI SDK](https://sdk.vercel.ai/) with a [Next.js](https://nextjs.org/docs) and [Wagmi](https://wagmi.sh/) dapp.
12+
13+
## Prerequisites
14+
15+
- [Node.js](https://nodejs.org/) version 18 or later and [pnpm](https://pnpm.io/installation) installed
16+
- An [OpenAI](https://platform.openai.com/docs/overview) API key, with some credit balance available
17+
- [MetaMask](https://metamask.io/) installed, with an account that has Linea Sepolia ETH
18+
:::note
19+
You can use the [MetaMask faucet](/developer-tools/faucet) to get Linea Sepolia ETH.
20+
:::
21+
22+
## Steps
23+
24+
### 1. Set up the project
25+
26+
1. Clone the [`Consensys/wallet-agent`](https://github.com/Consensys/wallet-agent/tree/main) repository:
27+
28+
```bash
29+
git clone [email protected]:Consensys/wallet-agent.git
30+
```
31+
32+
2. Switch to the `initial-setup` branch:
33+
34+
```bash
35+
cd wallet-agent && git switch initial-setup
36+
```
37+
38+
3. Install dependencies:
39+
40+
```bash
41+
npm install
42+
```
43+
44+
4. Create a `.env.local` file:
45+
46+
```bash
47+
touch .env.local
48+
```
49+
50+
5. In `.env.local`, add an `OPENAI_API_KEY` environment variable, replacing `<YOUR-API-KEY>` with your [OpenAI](https://platform.openai.com/docs/overview) API key.
51+
Vercel's AI SDK will use this environment variable to authenticate your dapp with the OpenAI service.
52+
53+
```text title=".env.local"
54+
OPENAI_API_KEY=<YOUR-API-KEY>
55+
```
56+
57+
### 2. Create the dapp interface
58+
59+
In `app/page.tsx`, use the `useAccount`, `useConnect`, and `useDisconnect` hooks from Wagmi, along with the Wagmi [MetaMask SDK connector](https://wagmi.sh/react/api/connectors/metaMask) to create a button to connect and disconnect your MetaMask wallet.
60+
61+
Use the `Chat` component to display the AI agent chat interface.
62+
63+
```tsx title="page.tsx"
64+
// add-next-line
65+
+ "use client";
66+
67+
// add-start
68+
+ import { useAccount, useConnect, useDisconnect } from "wagmi";
69+
+ import { metaMask } from "wagmi/connectors";
70+
+ import { Button } from "@/components/ui/button";
71+
+ import { Chat } from "@/components/Chat";
72+
// add-end
73+
import Image from "next/image";
74+
75+
// add-start
76+
+ const ConnectButton = () => {
77+
+ const { connect } = useConnect();
78+
+ const { address, isConnected } = useAccount();
79+
+ const { disconnect } = useDisconnect();
80+
+
81+
+ return (
82+
+ <div className="mx-auto">
83+
+ {isConnected ? (
84+
+ <Button onClick={() => disconnect()}>Disconnect {address}</Button>
85+
+ ) : (
86+
+ <Button onClick={() => connect({ connector: metaMask() })}>Connect</Button>
87+
+ )}
88+
+ </div>
89+
+ );
90+
+ };
91+
// add-end
92+
93+
export default function Home() {
94+
// add-next-line
95+
+ const { isConnected } = useAccount();
96+
return (
97+
<div className="h-screen w-full overflow-y-auto grid grid-rows-[20px_1fr_20px] items-center justify-items-center min-h-screen p-8 pb-20 gap-16 sm:p-20 font-[family-name:var(--font-geist-sans)]">
98+
<main className="gap-8 row-start-2 sm:items-start h-full w-full">
99+
<h1>Wallet Agent setup</h1>
100+
// add-start
101+
+ <ConnectButton />
102+
+ { isConnected ? <Chat /> : null}
103+
// add-end
104+
</main>
105+
// ...
106+
```
107+
108+
To test the interface, run the development server and navigate to [`http://localhost:3000`](http://localhost:3000/):
109+
110+
```bash
111+
npm run dev
112+
```
113+
114+
Test that the button works to connect and disconnect from your MetaMask wallet.
115+
When connected, the AI agent chat interface displays with your connected wallet address.
116+
You can test the AI functionality by sending messages in the chat:
117+
118+
<p align="center">
119+
<img src={require("../_assets/sdk-ai-agent.png").default} alt="SDK AI agent initial setup" class="appScreen" />
120+
</p>
121+
122+
### 3. Create a Public Client
123+
124+
In `wagmi.config.ts`, initialize a [Viem Public Client](https://viem.sh/docs/clients/public.html)
125+
with the Linea Sepolia chain.
126+
This Public Client will enable the AI agent to access public JSON-RPC API methods such as retrieving balances:
127+
128+
```ts title="wagmi.config.ts"
129+
// add-next-line
130+
+ import { createPublicClient } from "viem";
131+
import { createConfig, http, cookieStorage, createStorage } from "wagmi";
132+
import { lineaSepolia, linea, mainnet } from "wagmi/chains";
133+
import { metaMask } from "wagmi/connectors";
134+
135+
// add-start
136+
+ export const publicClient = createPublicClient({
137+
+ chain: lineaSepolia,
138+
+ transport: http(),
139+
+ });
140+
// add-end
141+
142+
export function getConfig() {
143+
// ...
144+
```
145+
146+
### 4. Create a tool to get the balance
147+
148+
Use the AI SDK's [tools](https://sdk.vercel.ai/docs/foundations/tools) feature to enable the AI agent to perform specific tasks.
149+
150+
In `ai/tools.ts`, update or remove the example tool.
151+
Use the [`getBalance`](https://viem.sh/docs/actions/public/getBalance) method of your configured Public Client, and Viem's [`formatEther`](https://viem.sh/docs/utilities/formatEther.html) function to create a tool that retrieves the ether balance of the connected wallet:
152+
153+
```ts title="tools.ts"
154+
// add-start
155+
+ import { publicClient } from "@/wagmi.config";
156+
+ import { formatEther } from "viem";
157+
// add-end
158+
import { tool as createTool } from "ai";
159+
import { z } from "zod";
160+
161+
// remove-start
162+
- const tool = createTool({
163+
- description: "Example tool",
164+
- parameters: z.object({
165+
- name: z.string().describe("The name of the user"),
166+
- }),
167+
- execute: async ({ name }) => {
168+
- return { name };
169+
- },
170+
- });
171+
//remove-end
172+
// add-start
173+
+ const balanceTool = createTool({
174+
+ description: "Get the balance of the connected wallet",
175+
+ parameters: z.object({
176+
+ address: z.string().describe("The address of the user"),
177+
+ }),
178+
+ execute: async ({ address }) => {
179+
+ const balance = await publicClient.getBalance({
180+
+ address: address as `0x${string}`,
181+
+ });
182+
+ return { balance: formatEther(balance) };
183+
+ },
184+
+ });
185+
// add-end
186+
187+
export const tools = {
188+
// remove-next-line
189+
- example: tool,
190+
// add-next-line
191+
+ displayBalance: balanceTool,
192+
};
193+
```
194+
195+
In the development server, test that this tool works to get your current Linea Sepolia ETH balance:
196+
197+
<p align="center">
198+
<img src={require("../_assets/sdk-ai-agent-get-balance.png").default} alt="SDK AI agent get balance" class="appScreen" />
199+
</p>
200+
201+
### 5. Create a tool to send transactions
202+
203+
In `ai/tools.ts`, create another tool to send transactions.
204+
In this example, the tool and the `Chat.tsx` component are configured to initiate a transaction and provide a button for you to send the transaction.
205+
You only need to make the following changes to the `tools.ts` file:
206+
207+
<Tabs>
208+
<TabItem value="ai/tools.ts">
209+
210+
```ts
211+
import { publicClient } from "@/wagmi.config";
212+
import { formatEther } from "viem";
213+
import { tool as createTool } from "ai";
214+
import { z } from "zod";
215+
216+
const balanceTool = createTool({
217+
// ...
218+
});
219+
220+
// add-start
221+
+ const sendTransactionTool = createTool({
222+
+ description: "Initiate a transaction to the provided wallet address",
223+
+ parameters: z.object({
224+
+ to: z.string().describe("The wallet address of the user"),
225+
+ amount: z.string().describe("The amount of ether to send"),
226+
+ }),
227+
+ execute: async ({ to, amount }) => {
228+
+ return { to, amount };
229+
+ },
230+
+ });
231+
// add-end
232+
233+
export const tools = {
234+
displayBalance: balanceTool,
235+
// add-next-line
236+
+ sendTransaction: sendTransactionTool,
237+
};
238+
```
239+
240+
</TabItem>
241+
<TabItem value="components/Chat.tsx">
242+
243+
```tsx
244+
// ...
245+
if (toolName === "sendTransaction") {
246+
const {
247+
result,
248+
}: { result: { to: string; amount: string } } =
249+
toolInvocation;
250+
251+
if (isLoading) {
252+
return (
253+
<div key={toolCallId}>
254+
<p>Loading...</p>
255+
</div>
256+
);
257+
}
258+
259+
return (
260+
<div key={toolCallId}>
261+
<Button
262+
className="bg-orange-600 text-orange-100 py-2 px-5 rounded-sm w-fit"
263+
onClick={() =>
264+
sendTransaction({
265+
to: result.to as `0x${string}`,
266+
value: parseEther(result.amount),
267+
})
268+
}
269+
>
270+
Send Transaction
271+
</Button>
272+
<p>
273+
{hash
274+
? `Transaction sent: ${hash}`
275+
: "Transaction not sent"}
276+
</p>
277+
</div>
278+
);
279+
}
280+
// ...
281+
```
282+
283+
</TabItem>
284+
</Tabs>
285+
286+
In the development server, test that this tool works to send Linea Sepolia ETH from your connected address to the address you provide.
287+
288+
When you request the agent to send a transaction, it will provide a button for you to send the transaction, but it will not send it for you:
289+
290+
<p align="center">
291+
<img src={require("../_assets/sdk-ai-agent-txn-not-sent.png").default} alt="NFT confirmation" class="appScreen" />
292+
</p>
293+
294+
When you select the button and confirm the transaction in MetaMask, the transaction will be sent:
295+
296+
<p align="center">
297+
<img src={require("../_assets/sdk-ai-agent-txn-sent.png").default} alt="Multiple NFTs confirmation" class="appScreen" />
298+
</p>
299+
300+
You can check the status of the transaction in the [Linea Sepolia block explorer](https://sepolia.lineascan.build/).
301+
302+
:::note
303+
You can configure the AI agent to directly send the transaction using a [Viem Wallet Client](https://viem.sh/docs/clients/wallet).
304+
:::
305+
306+
## Resources
307+
308+
- View the main branch of the [`Consensys/wallet-agent`](https://github.com/Consensys/wallet-agent) template for the completed implementation of this tutorial.
309+
- Watch the [live coding session](https://www.youtube.com/watch?v=ZVuOaKuAhBQ) on YouTube, in which the MetaMask DevRel team walks through creating a wallet AI agent from the initial template.

src/scss/custom.scss

+16
Original file line numberDiff line numberDiff line change
@@ -624,3 +624,19 @@ ol {
624624
max-width: 80rem;
625625
}
626626
}
627+
628+
.git-diff-remove {
629+
background-color: #ff000020;
630+
display: block;
631+
margin: 0 calc(-1 * var(--ifm-pre-padding));
632+
padding: 0 var(--ifm-pre-padding);
633+
border-left: 3px solid #ff000080;
634+
}
635+
636+
.git-diff-add {
637+
background-color: #1aff0020;
638+
display: block;
639+
margin: 0 calc(-1 * var(--ifm-pre-padding));
640+
padding: 0 var(--ifm-pre-padding);
641+
border-left: 3px solid #1aff0080;
642+
}

0 commit comments

Comments
 (0)