Skip to content

Commit 7f2f788

Browse files
committed
added gaia example
1 parent 9bacb0f commit 7f2f788

File tree

3 files changed

+275
-1
lines changed

3 files changed

+275
-1
lines changed

.env.example

+6-1
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,9 @@ ENCRYPTION_KEY= # a second random 32 bytes encryption key for local db encryptio
55
OPENAI_API_KEY= # the API key for the OpenAI
66

77
# gated group example
8-
ALCHEMY_API_KEY= # the API key for the Alchemy
8+
ALCHEMY_API_KEY= # the API key for the Alchemy
9+
10+
# Gaia Node example
11+
GAIA_NODE_URL= # the URL of the Gaia node (Ex: https://llama8b.gaia.domains/v1)
12+
GAIA_API_KEY= # the API key for the Gaia node (Ex: gaia-xxxxxxxxxx)
13+
GAIA_MODEL_NAME= # the name of model running on your Gaia node (Ex: llama)

examples/gaia/README.md

+149
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
# GPT agent example
2+
3+
This example uses a [Gaia](https://docs.gaianet.ai) API for AI based responses and [XMTP](https://xmtp.org) for secure messaging. You can test your agent on [xmtp.chat](https://xmtp.chat) or any other XMTP-compatible client.
4+
5+
Using Gaia, you can also run your own [node](https://docs.gaianet.ai/getting-started/quick-start) and use the OpenAI compatible API in this library.
6+
7+
## Environment variables
8+
9+
Add the following keys to a `.env` file:
10+
11+
```bash
12+
WALLET_KEY= # the private key of the wallet
13+
ENCRYPTION_KEY= # a second random 32 bytes encryption key for local db encryption
14+
GAIA_API_KEY= # Your API key from https://gaianet.ai
15+
GAIA_NODE_URL= # Your custom Gaia node URL or a public node, ex: https://llama8b.gaia.domains/v1
16+
GAIA_MODEL_NAME= # Model name running in your Gaia node or a public node, ex: llama
17+
```
18+
19+
You can generate random keys with the following command:
20+
21+
```bash
22+
yarn gen:keys
23+
```
24+
25+
> [!WARNING]
26+
> Running the `gen:keys` script will overwrite the existing `.env` file.
27+
28+
## Usage
29+
30+
```tsx
31+
import { Client, type XmtpEnv } from "@xmtp/node-sdk";
32+
import OpenAI from "openai";
33+
import { createSigner, getEncryptionKeyFromHex } from "@/helpers";
34+
35+
const { WALLET_KEY, ENCRYPTION_KEY, GAIA_NODE_URL, GAIA_API_KEY, GAIA_MODEL_NAME } = process.env;
36+
37+
if (!WALLET_KEY) {
38+
throw new Error("WALLET_KEY must be set");
39+
}
40+
41+
if (!ENCRYPTION_KEY) {
42+
throw new Error("ENCRYPTION_KEY must be set");
43+
}
44+
45+
/* Check if the Gaia API key is set */
46+
if (!GAIA_API_KEY) {
47+
throw new Error("GAIA_API_KEY must be set");
48+
}
49+
50+
/* Check if the Gaia node's base URL is set */
51+
if (!GAIA_NODE_URL) {
52+
throw new Error("GAIA_NODE_URL must be set");
53+
}
54+
55+
/* Check if the the model name for the Gaia node is set */
56+
if (!GAIA_MODEL_NAME) {
57+
throw new Error("GAIA_MODEL_NAME must be set");
58+
}
59+
60+
const signer = createSigner(WALLET_KEY);
61+
const encryptionKey = getEncryptionKeyFromHex(ENCRYPTION_KEY);
62+
const openai = new OpenAI({
63+
baseURL: GAIA_NODE_URL,
64+
apiKey: GAIA_API_KEY
65+
});
66+
67+
/* Set the environment to dev or production */
68+
const env: XmtpEnv = "dev";
69+
70+
async function main() {
71+
console.log(`Creating client on the '${env}' network...`);
72+
const client = await Client.create(signer, encryptionKey, {
73+
env,
74+
});
75+
76+
console.log("Syncing conversations...");
77+
/* Sync the conversations from the network to update the local db */
78+
await client.conversations.sync();
79+
80+
console.log(
81+
`Agent initialized on ${client.accountAddress}\nSend a message on http://xmtp.chat/dm/${client.accountAddress}`,
82+
);
83+
84+
console.log("Waiting for messages...");
85+
const stream = client.conversations.streamAllMessages();
86+
87+
for await (const message of await stream) {
88+
/* Ignore messages from the same agent or non-text messages */
89+
if (
90+
message?.senderInboxId.toLowerCase() === client.inboxId.toLowerCase() ||
91+
message?.contentType?.typeId !== "text"
92+
) {
93+
continue;
94+
}
95+
96+
console.log(
97+
`Received message: ${message.content as string} by ${message.senderInboxId}`,
98+
);
99+
100+
const conversation = client.conversations.getConversationById(
101+
message.conversationId,
102+
);
103+
104+
if (!conversation) {
105+
console.log("Unable to find conversation, skipping");
106+
continue;
107+
}
108+
109+
try {
110+
const completion = await openai.chat.completions.create({
111+
messages: [{ role: "user", content: message.content as string }],
112+
model: GAIA_MODEL_NAME,
113+
});
114+
115+
/* Get the AI response */
116+
const response =
117+
completion.choices[0]?.message?.content ||
118+
"I'm not sure how to respond to that.";
119+
120+
console.log(`Sending AI response: ${response}`);
121+
await conversation.send(response);
122+
} catch (error) {
123+
console.error("Error getting AI response:", error);
124+
await conversation.send(
125+
"Sorry, I encountered an error processing your message.",
126+
);
127+
}
128+
129+
console.log("Waiting for messages...");
130+
}
131+
}
132+
133+
main().catch(console.error);
134+
```
135+
136+
## Run the agent
137+
138+
```bash
139+
# git clone repo
140+
git clone https://github.com/ephemeraHQ/xmtp-agent-examples.git
141+
# go to the folder
142+
cd xmtp-agent-examples
143+
# install packages
144+
yarn
145+
# generate random keys (optional)
146+
yarn gen:keys
147+
# run the example
148+
yarn examples:gpt
149+
```

examples/gaia/index.ts

+120
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
import { Client, type XmtpEnv } from "@xmtp/node-sdk";
2+
import OpenAI from "openai";
3+
import { createSigner, getEncryptionKeyFromHex } from "@/helpers";
4+
5+
/* Get the wallet key associated to the public key of
6+
* the agent and the encryption key for the local db
7+
* that stores your agent's messages */
8+
const { WALLET_KEY, ENCRYPTION_KEY, GAIA_NODE_URL, GAIA_API_KEY, GAIA_MODEL_NAME } = process.env;
9+
10+
/* Check if the environment variables are set */
11+
if (!WALLET_KEY) {
12+
throw new Error("WALLET_KEY must be set");
13+
}
14+
15+
/* Check if the encryption key is set */
16+
if (!ENCRYPTION_KEY) {
17+
throw new Error("ENCRYPTION_KEY must be set");
18+
}
19+
20+
/* Check if the OpenAI API key is set */
21+
if (!GAIA_API_KEY) {
22+
throw new Error("GAIA_API_KEY must be set");
23+
}
24+
25+
/* Check if the Gaia node's base URL is set */
26+
if (!GAIA_NODE_URL) {
27+
throw new Error("GAIA_NODE_URL must be set");
28+
}
29+
30+
/* Check if the the model name for the Gaia node is set */
31+
if (!GAIA_MODEL_NAME) {
32+
throw new Error("GAIA_MODEL_NAME must be set");
33+
}
34+
35+
/* Create the signer using viem and parse the encryption key for the local db */
36+
const signer = createSigner(WALLET_KEY);
37+
const encryptionKey = getEncryptionKeyFromHex(ENCRYPTION_KEY);
38+
39+
/* Initialize the OpenAI client */
40+
const openai = new OpenAI({
41+
baseURL: GAIA_NODE_URL,
42+
apiKey: GAIA_API_KEY
43+
});
44+
45+
/* Set the environment to dev or production */
46+
const env: XmtpEnv = "dev";
47+
48+
/**
49+
* Main function to run the agent
50+
*/
51+
async function main() {
52+
console.log(`Creating client on the '${env}' network...`);
53+
/* Initialize the xmtp client */
54+
const client = await Client.create(signer, encryptionKey, {
55+
env,
56+
});
57+
58+
console.log("Syncing conversations...");
59+
/* Sync the conversations from the network to update the local db */
60+
await client.conversations.sync();
61+
62+
console.log(
63+
`Agent initialized on ${client.accountAddress}\nSend a message on http://xmtp.chat/dm/${client.accountAddress}`,
64+
);
65+
66+
console.log("Waiting for messages...");
67+
/* Stream all messages from the network */
68+
const stream = client.conversations.streamAllMessages();
69+
70+
for await (const message of await stream) {
71+
/* Ignore messages from the same agent or non-text messages */
72+
if (
73+
message?.senderInboxId.toLowerCase() === client.inboxId.toLowerCase() ||
74+
message?.contentType?.typeId !== "text"
75+
) {
76+
continue;
77+
}
78+
79+
console.log(
80+
`Received message: ${message.content as string} by ${message.senderInboxId}`,
81+
);
82+
83+
/* Get the conversation from the local db */
84+
const conversation = client.conversations.getConversationById(
85+
message.conversationId,
86+
);
87+
88+
/* If the conversation is not found, skip the message */
89+
if (!conversation) {
90+
console.log("Unable to find conversation, skipping");
91+
continue;
92+
}
93+
94+
try {
95+
/* Get the AI response */
96+
const completion = await openai.chat.completions.create({
97+
messages: [{ role: "user", content: message.content as string }],
98+
model: GAIA_MODEL_NAME,
99+
});
100+
101+
/* Get the AI response */
102+
const response =
103+
completion.choices[0]?.message?.content ||
104+
"I'm not sure how to respond to that.";
105+
106+
console.log(`Sending AI response: ${response}`);
107+
/* Send the AI response to the conversation */
108+
await conversation.send(response);
109+
} catch (error) {
110+
console.error("Error getting AI response:", error);
111+
await conversation.send(
112+
"Sorry, I encountered an error processing your message.",
113+
);
114+
}
115+
116+
console.log("Waiting for messages...");
117+
}
118+
}
119+
120+
main().catch(console.error);

0 commit comments

Comments
 (0)