create-message-kit 1.2.22 → 1.2.23
Sign up to get free protection for your applications and to get access to all the features.
- package/README.md +2 -5
- package/index.js +2 -3
- package/package.json +1 -1
- package/templates/coinbase-agent/src/index.ts +5 -7
- package/templates/ens/src/index.ts +4 -24
- package/templates/ens/src/skills/info.ts +6 -3
- package/templates/faucet/src/index.ts +5 -16
- package/templates/gated-group/src/index.ts +2 -2
- package/templates/gm/src/index.ts +15 -7
- package/templates/hackathon-store/.cursorrules +290 -0
- package/templates/hackathon-store/.env.example +6 -0
- package/templates/hackathon-store/.yarnrc.yml +9 -0
- package/templates/hackathon-store/package.json +20 -0
- package/templates/hackathon-store/src/index.ts +47 -0
- package/templates/hackathon-store/src/plugins/notion.ts +60 -0
- package/templates/hackathon-store/src/prompt.md +27 -0
- package/templates/playground/src/index.ts +9 -8
- package/templates/playground/src/vibes/chill.ts +9 -0
- package/templates/playground/src/vibes/friendly.ts +9 -0
- package/templates/playground/src/vibes/inquisitive.ts +10 -0
- package/templates/playground/src/vibes/playful.ts +10 -0
- package/templates/playground/src/vibes/professional.ts +9 -0
- package/templates/simple/src/index.ts +10 -9
- package/templates/toss/.env.example +1 -0
- package/templates/toss/src/index.ts +7 -10
- package/templates/toss/src/skills/toss.ts +0 -114
- package/templates/toss/src/skills/waas.ts +116 -0
- package/templates.json +2 -2
package/README.md
CHANGED
@@ -9,13 +9,10 @@ bun create message-kit
|
|
9
9
|
```
|
10
10
|
|
11
11
|
```bash
|
12
|
-
npx create-message-kit
|
12
|
+
npx create-message-kit@latest
|
13
13
|
```
|
14
14
|
|
15
15
|
```bash
|
16
16
|
yarn create message-kit
|
17
|
-
|
18
|
-
|
19
|
-
```bash [npm]
|
20
|
-
npm init message-kit
|
17
|
+
// use yarn create message-kit@latest in yarn > v2
|
21
18
|
```
|
package/index.js
CHANGED
@@ -7,7 +7,7 @@ import { default as fs } from "fs-extra";
|
|
7
7
|
import { isCancel } from "@clack/prompts";
|
8
8
|
import { detect } from "detect-package-manager";
|
9
9
|
import pc from "picocolors";
|
10
|
-
const defVersion = "1.2.
|
10
|
+
const defVersion = "1.2.23";
|
11
11
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
12
12
|
|
13
13
|
// Read package.json to get the version
|
@@ -219,8 +219,7 @@ async function detectPackageManager() {
|
|
219
219
|
|
220
220
|
const userAgent = process.env.npm_config_user_agent;
|
221
221
|
|
222
|
-
|
223
|
-
if (userAgent?.startsWith("npm")) {
|
222
|
+
if (userAgent?.startsWith("npm") || userAgent?.startsWith("npx")) {
|
224
223
|
return "npm";
|
225
224
|
}
|
226
225
|
|
package/package.json
CHANGED
@@ -14,11 +14,8 @@ export const agent: Agent = {
|
|
14
14
|
name: "Swap Bot",
|
15
15
|
tag: "@base",
|
16
16
|
description: "Swap bot for base.",
|
17
|
-
skills: [
|
18
|
-
|
19
|
-
|
20
|
-
run(
|
21
|
-
async (context: XMTPContext) => {
|
17
|
+
skills: [swapSkill, mintSkill, dripSkill, paySkill],
|
18
|
+
onMessage: async (context: XMTPContext) => {
|
22
19
|
const {
|
23
20
|
message: { sender },
|
24
21
|
agent,
|
@@ -27,5 +24,6 @@ run(
|
|
27
24
|
let prompt = await replaceVariables(systemPrompt, sender.address, agent);
|
28
25
|
await agentReply(context, prompt);
|
29
26
|
},
|
30
|
-
|
31
|
-
|
27
|
+
};
|
28
|
+
|
29
|
+
run(agent);
|
@@ -13,41 +13,21 @@ import { register } from "./skills/register.js";
|
|
13
13
|
import { renew } from "./skills/renew.js";
|
14
14
|
import { pay } from "./skills/pay.js";
|
15
15
|
import { reset } from "./skills/reset.js";
|
16
|
-
import fs from "fs";
|
17
16
|
|
18
|
-
// [!region skills]
|
19
17
|
export const agent: Agent = {
|
20
18
|
name: "Ens Agent",
|
21
19
|
tag: "@bot",
|
22
20
|
description: "A ens agent with a lot of skills.",
|
23
|
-
skills: [
|
24
|
-
|
25
|
-
...cool,
|
26
|
-
...info,
|
27
|
-
...register,
|
28
|
-
...renew,
|
29
|
-
...reset,
|
30
|
-
...pay,
|
31
|
-
],
|
32
|
-
};
|
33
|
-
// [!endregion skills]
|
34
|
-
|
35
|
-
// [!region run1]
|
36
|
-
run(
|
37
|
-
async (context: XMTPContext) => {
|
21
|
+
skills: [checkDomain, cool, info, register, renew, reset, pay],
|
22
|
+
onMessage: async (context: XMTPContext) => {
|
38
23
|
const {
|
39
24
|
message: { sender },
|
40
25
|
agent,
|
41
26
|
} = context;
|
42
27
|
|
43
28
|
let prompt = await replaceVariables(systemPrompt, sender.address, agent);
|
44
|
-
// [!endregion run1]
|
45
|
-
//This is only used for to update the docs.
|
46
|
-
fs.writeFileSync("example_prompt.md", prompt);
|
47
|
-
// [!region run2]
|
48
29
|
await agentReply(context, prompt);
|
49
30
|
},
|
50
|
-
|
51
|
-
);
|
31
|
+
};
|
52
32
|
|
53
|
-
|
33
|
+
run(agent);
|
@@ -48,9 +48,12 @@ export async function handler(context: XMTPContext) {
|
|
48
48
|
message += `\n\nWould you like to tip the domain owner for getting there first 🤣?`;
|
49
49
|
message = message.trim();
|
50
50
|
|
51
|
-
|
52
|
-
|
53
|
-
|
51
|
+
const { v2, v3 } = await context.isOnXMTP(
|
52
|
+
context.client,
|
53
|
+
context.v2client,
|
54
|
+
sender?.address,
|
55
|
+
);
|
56
|
+
if (v2 || v3) {
|
54
57
|
await context.send(
|
55
58
|
`Ah, this domains is in XMTP, you can message it directly`,
|
56
59
|
);
|
@@ -7,33 +7,22 @@ import {
|
|
7
7
|
} from "@xmtp/message-kit";
|
8
8
|
import { systemPrompt } from "./prompt.js";
|
9
9
|
import { faucet } from "./skills/faucet.js";
|
10
|
-
import fs from "fs";
|
11
10
|
|
12
11
|
// [!region skills]
|
13
12
|
export const agent: Agent = {
|
14
13
|
name: "Faucet Agent",
|
15
14
|
tag: "@bot",
|
16
15
|
description: "A faucet delivery agent.",
|
17
|
-
skills: [
|
18
|
-
|
19
|
-
// [!endregion skills]
|
20
|
-
|
21
|
-
// [!region run1]
|
22
|
-
run(
|
23
|
-
async (context: XMTPContext) => {
|
16
|
+
skills: [faucet],
|
17
|
+
onMessage: async (context: XMTPContext) => {
|
24
18
|
const {
|
25
19
|
message: { sender },
|
26
20
|
agent,
|
27
21
|
} = context;
|
28
22
|
|
29
23
|
let prompt = await replaceVariables(systemPrompt, sender.address, agent);
|
30
|
-
|
31
|
-
//This is only used for to update the docs.
|
32
|
-
fs.writeFileSync("example_prompt.md", prompt);
|
33
|
-
// [!region run2]
|
24
|
+
|
34
25
|
await agentReply(context, prompt);
|
35
26
|
},
|
36
|
-
|
37
|
-
);
|
38
|
-
|
39
|
-
// [!endregion run2]
|
27
|
+
};
|
28
|
+
run(agent);
|
@@ -1,8 +1,16 @@
|
|
1
|
-
import { run } from "@xmtp/message-kit";
|
1
|
+
import { run, Agent } from "@xmtp/message-kit";
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
3
|
+
const agent: Agent = {
|
4
|
+
name: "Gm Bot",
|
5
|
+
tag: "@bot",
|
6
|
+
description: "Gm bot.",
|
7
|
+
skills: [],
|
8
|
+
onMessage: async (context) => {
|
9
|
+
const { group } = context;
|
10
|
+
if (!group) {
|
11
|
+
await context.send(`gm`);
|
12
|
+
}
|
13
|
+
},
|
14
|
+
};
|
15
|
+
|
16
|
+
run(agent);
|
@@ -0,0 +1,290 @@
|
|
1
|
+
# MessageKit Skill Template
|
2
|
+
|
3
|
+
## Examples
|
4
|
+
|
5
|
+
### Check if a Domain is Available
|
6
|
+
|
7
|
+
|
8
|
+
import { ensUrl } from "../index.js";
|
9
|
+
import { XMTPContext } from "@xmtp/message-kit";
|
10
|
+
import type { Skill } from "@xmtp/message-kit";
|
11
|
+
|
12
|
+
// Define Skill
|
13
|
+
export const checkDomain: Skill[] = [
|
14
|
+
{
|
15
|
+
skill: "check",
|
16
|
+
handler: handler,
|
17
|
+
examples: ["/check vitalik.eth", "/check fabri.base.eth"],
|
18
|
+
description: "Check if a domain is available.",
|
19
|
+
params: {
|
20
|
+
domain: {
|
21
|
+
type: "string",
|
22
|
+
},
|
23
|
+
},
|
24
|
+
},
|
25
|
+
];
|
26
|
+
|
27
|
+
// Handler Implementation
|
28
|
+
export async function handler(context: XMTPContext) {
|
29
|
+
const {
|
30
|
+
message: {
|
31
|
+
content: {
|
32
|
+
params: { domain },
|
33
|
+
},
|
34
|
+
},
|
35
|
+
} = context;
|
36
|
+
|
37
|
+
const data = await context.getUserInfo(domain);
|
38
|
+
|
39
|
+
if (!data?.address) {
|
40
|
+
let message = `Looks like ${domain} is available! Here you can register it: ${ensUrl}${domain} or would you like to see some cool alternatives?`;
|
41
|
+
return {
|
42
|
+
code: 200,
|
43
|
+
message,
|
44
|
+
};
|
45
|
+
} else {
|
46
|
+
let message = `Looks like ${domain} is already registered!`;
|
47
|
+
await context.executeSkill("/cool " + domain);
|
48
|
+
return {
|
49
|
+
code: 404,
|
50
|
+
message,
|
51
|
+
};
|
52
|
+
}
|
53
|
+
}
|
54
|
+
|
55
|
+
### Generate a payment request
|
56
|
+
|
57
|
+
|
58
|
+
import { XMTPContext } from "@xmtp/message-kit";
|
59
|
+
import type { Skill } from "@xmtp/message-kit";
|
60
|
+
|
61
|
+
// Define Skill
|
62
|
+
export const paymentRequest: Skill[] = [
|
63
|
+
{
|
64
|
+
skill: "pay",
|
65
|
+
examples: [
|
66
|
+
"/pay 10 vitalik.eth",
|
67
|
+
"/pay 1 usdc to 0xC60E6Bb79322392761BFe3081E302aEB79B30B03",
|
68
|
+
],
|
69
|
+
description:
|
70
|
+
"Send a specified amount of a cryptocurrency to a destination address. \nWhen tipping, you can assume it's 1 USDC.",
|
71
|
+
handler: handler,
|
72
|
+
params: {
|
73
|
+
amount: {
|
74
|
+
default: 10,
|
75
|
+
type: "number",
|
76
|
+
},
|
77
|
+
token: {
|
78
|
+
default: "usdc",
|
79
|
+
type: "string",
|
80
|
+
values: ["eth", "dai", "usdc", "degen"], // Accepted tokens
|
81
|
+
},
|
82
|
+
username: {
|
83
|
+
default: "",
|
84
|
+
type: "username",
|
85
|
+
},
|
86
|
+
address: {
|
87
|
+
default: "",
|
88
|
+
type: "address",
|
89
|
+
},
|
90
|
+
},
|
91
|
+
},
|
92
|
+
];
|
93
|
+
|
94
|
+
// Handler Implementation
|
95
|
+
export async function handler(context: XMTPContext) {
|
96
|
+
const {
|
97
|
+
message: {
|
98
|
+
content: {
|
99
|
+
params: { amount, token, username, address },
|
100
|
+
},
|
101
|
+
},
|
102
|
+
} = context;
|
103
|
+
let receiverAddress = address;
|
104
|
+
if (username) {
|
105
|
+
receiverAddress = (await context.getUserInfo(username))?.address;
|
106
|
+
}
|
107
|
+
if (address) {
|
108
|
+
// Prioritize address over username
|
109
|
+
receiverAddress = address;
|
110
|
+
}
|
111
|
+
|
112
|
+
await context.requestPayment(amount, token, receiverAddress);
|
113
|
+
}
|
114
|
+
|
115
|
+
|
116
|
+
## Types
|
117
|
+
|
118
|
+
import { XMTPContext } from "../plugins/xmtp.js";
|
119
|
+
import { ClientOptions, GroupMember } from "@xmtp/node-sdk";
|
120
|
+
import { ContentTypeId } from "@xmtp/content-type-primitives";
|
121
|
+
|
122
|
+
export type MessageAbstracted = {
|
123
|
+
id: string;
|
124
|
+
sent: Date;
|
125
|
+
content: {
|
126
|
+
text?: string | undefined;
|
127
|
+
reply?: string | undefined;
|
128
|
+
previousMsg?: string | undefined;
|
129
|
+
react?: string | undefined;
|
130
|
+
content?: any | undefined;
|
131
|
+
params?: any | undefined;
|
132
|
+
reference?: string | undefined;
|
133
|
+
skill?: string | undefined;
|
134
|
+
};
|
135
|
+
version: "v2" | "v3";
|
136
|
+
sender: AbstractedMember;
|
137
|
+
typeId: string;
|
138
|
+
};
|
139
|
+
export type GroupAbstracted = {
|
140
|
+
id: string;
|
141
|
+
sync: () => Promise<void>;
|
142
|
+
addMembers: (addresses: string[]) => Promise<void>;
|
143
|
+
addMembersByInboxId: (inboxIds: string[]) => Promise<void>;
|
144
|
+
send: (content: string, contentType?: ContentTypeId) => Promise<string>;
|
145
|
+
isAdmin: (inboxId: string) => boolean;
|
146
|
+
isSuperAdmin: (inboxId: string) => boolean;
|
147
|
+
admins: string[];
|
148
|
+
superAdmins: string[];
|
149
|
+
createdAt: Date;
|
150
|
+
members: GroupMember[];
|
151
|
+
};
|
152
|
+
export type SkillResponse = {
|
153
|
+
code: number;
|
154
|
+
message: string;
|
155
|
+
data?: any;
|
156
|
+
};
|
157
|
+
|
158
|
+
export type SkillHandler = (
|
159
|
+
context: XMTPContext,
|
160
|
+
) => Promise<SkillResponse | void>;
|
161
|
+
|
162
|
+
export type Handler = (context: XMTPContext) => Promise<void>;
|
163
|
+
|
164
|
+
export type RunConfig = {
|
165
|
+
// client options from XMTP client
|
166
|
+
client?: ClientOptions;
|
167
|
+
// private key to be used for the client, if not, default from env
|
168
|
+
privateKey?: string;
|
169
|
+
// if true, the init log message with messagekit logo and stuff will be hidden
|
170
|
+
experimental?: boolean;
|
171
|
+
// hide the init log message with messagekit logo and stuff
|
172
|
+
hideInitLogMessage?: boolean;
|
173
|
+
// if true, attachments will be enabled
|
174
|
+
attachments?: boolean;
|
175
|
+
// if true, member changes will be enabled, like adding members to the group
|
176
|
+
memberChange?: boolean;
|
177
|
+
// skills to be used
|
178
|
+
agent?: Agent;
|
179
|
+
// model to be used
|
180
|
+
gptModel?: string;
|
181
|
+
};
|
182
|
+
export interface SkillParamConfig {
|
183
|
+
default?: string | number | boolean;
|
184
|
+
type:
|
185
|
+
| "number"
|
186
|
+
| "string"
|
187
|
+
| "username"
|
188
|
+
| "quoted"
|
189
|
+
| "address"
|
190
|
+
| "prompt"
|
191
|
+
| "url";
|
192
|
+
plural?: boolean;
|
193
|
+
values?: string[]; // Accepted values for the parameter
|
194
|
+
}
|
195
|
+
|
196
|
+
export interface Frame {
|
197
|
+
title: string;
|
198
|
+
buttons: { content: string; action: string; target: string }[];
|
199
|
+
image: string;
|
200
|
+
}
|
201
|
+
export interface Agent {
|
202
|
+
name: string;
|
203
|
+
description: string;
|
204
|
+
tag: string;
|
205
|
+
skills: Skill[];
|
206
|
+
}
|
207
|
+
export interface Skill {
|
208
|
+
skill: string;
|
209
|
+
handler?: SkillHandler | undefined;
|
210
|
+
adminOnly?: boolean;
|
211
|
+
description: string;
|
212
|
+
examples: string[];
|
213
|
+
params: Record<string, SkillParamConfig>;
|
214
|
+
}
|
215
|
+
|
216
|
+
export interface AbstractedMember {
|
217
|
+
inboxId: string;
|
218
|
+
address: string;
|
219
|
+
accountAddresses: string[];
|
220
|
+
installationIds?: string[];
|
221
|
+
}
|
222
|
+
|
223
|
+
export type MetadataValue = string | number | boolean;
|
224
|
+
export type Metadata = Record<string, MetadataValue | MetadataValue[]>;
|
225
|
+
|
226
|
+
|
227
|
+
## Example final prompt
|
228
|
+
|
229
|
+
Your are a helpful and playful ens agent called @bot that lives inside a messaging app called Converse.
|
230
|
+
|
231
|
+
|
232
|
+
# Rules
|
233
|
+
- You can respond with multiple messages if needed. Each message should be separated by a newline character.
|
234
|
+
- You can trigger skills by only sending the command in a newline message.
|
235
|
+
- Each command starts with a slash (/).
|
236
|
+
- Never announce actions without using a command separated by a newline character.
|
237
|
+
- Never use markdown in your responses.
|
238
|
+
- Do not make guesses or assumptions
|
239
|
+
- Only answer if the verified information is in the prompt.
|
240
|
+
- Check that you are not missing a command
|
241
|
+
- Focus only on helping users with operations detailed below.
|
242
|
+
- Date: Fri, 06 Dec 2024 16:03:22 GMT
|
243
|
+
- When mentioning any action related to available skills, you MUST trigger the corresponding command in a new line
|
244
|
+
- If you suggest an action that has a command, you must trigger that command
|
245
|
+
|
246
|
+
|
247
|
+
## User context
|
248
|
+
- Start by fetch their domain from or Converse username
|
249
|
+
- Call the user by their name or domain, in case they have one
|
250
|
+
- Ask for a name (if they don't have one) so you can suggest domains.
|
251
|
+
- Message sent date: 2024-12-06T16:03:36.582Z
|
252
|
+
- Users address is: 0x40f08f0f853d1c42c61815652b7ccd5a50f0be09
|
253
|
+
- Users name is: ArizonaOregon
|
254
|
+
- Converse username is: ArizonaOregon
|
255
|
+
|
256
|
+
## Commands
|
257
|
+
/check [domain] - Check if a domain is available.
|
258
|
+
/cool [domain] - Get cool alternatives for a .eth domain.
|
259
|
+
/info [domain] - Get detailed information about an ENS domain including owner, expiry date, and resolver.
|
260
|
+
/register [domain] - Register a new ENS domain. Returns a URL to complete the registration process.
|
261
|
+
/renew [domain] - Extend the registration period of your ENS domain. Returns a URL to complete the renewal.
|
262
|
+
/reset - Reset the conversation clearing memory and usernames cache.
|
263
|
+
/pay [amount] [token] [username] [address] - Send a specified amount of a cryptocurrency to a destination address.
|
264
|
+
When tipping, you can asume its 1 usdc.
|
265
|
+
|
266
|
+
## Examples
|
267
|
+
/check vitalik.eth
|
268
|
+
/check fabri.base.eth
|
269
|
+
/cool vitalik.eth
|
270
|
+
/info nick.eth
|
271
|
+
/register vitalik.eth
|
272
|
+
/renew fabri.base.eth
|
273
|
+
/reset
|
274
|
+
/pay 10 vitalik.eth
|
275
|
+
/pay 1 usdc to 0xC60E6Bb79322392761BFe3081E302aEB79B30B03
|
276
|
+
|
277
|
+
## Scenarios
|
278
|
+
1. Missing commands in responses
|
279
|
+
**Issue**: Sometimes responses are sent without the required command.
|
280
|
+
**Example**:
|
281
|
+
Incorrect:
|
282
|
+
> "Looks like vitalik.eth is registered! What about these cool alternatives?"
|
283
|
+
Correct:
|
284
|
+
> "Looks like vitalik.eth is registered! What about these cool alternatives?
|
285
|
+
> /cool vitalik.eth"
|
286
|
+
|
287
|
+
Incorrect:
|
288
|
+
> Here is a summary of your TODOs. I will now send it via email.
|
289
|
+
Correct:
|
290
|
+
> /todo
|
@@ -0,0 +1,20 @@
|
|
1
|
+
{
|
2
|
+
"name": "hackathon-store",
|
3
|
+
"private": true,
|
4
|
+
"type": "module",
|
5
|
+
"scripts": {
|
6
|
+
"build": "tsc",
|
7
|
+
"dev": "tsc -w & sleep 1 && NODE_NO_WARNINGS=1 node --watch dist/index.js",
|
8
|
+
"start": "node dist/index.js"
|
9
|
+
},
|
10
|
+
"dependencies": {
|
11
|
+
"@notionhq/client": "^2.2.15",
|
12
|
+
"@redis/client": "^1.6.0",
|
13
|
+
"@xmtp/message-kit": "workspace:*",
|
14
|
+
"axios": "^1.7.7",
|
15
|
+
"lowdb": "^7.0.1"
|
16
|
+
},
|
17
|
+
"engines": {
|
18
|
+
"node": ">=20"
|
19
|
+
}
|
20
|
+
}
|
@@ -0,0 +1,47 @@
|
|
1
|
+
import {
|
2
|
+
agentReply,
|
3
|
+
XMTPContext,
|
4
|
+
replaceVariables,
|
5
|
+
run,
|
6
|
+
} from "@xmtp/message-kit";
|
7
|
+
import { downloadPage } from "./plugins/notion.js";
|
8
|
+
import fs from "fs";
|
9
|
+
import { Agent } from "@xmtp/message-kit";
|
10
|
+
setupFiles();
|
11
|
+
|
12
|
+
const agent: Agent = {
|
13
|
+
name: "Hackathon Store",
|
14
|
+
tag: "@store",
|
15
|
+
description: "Hackathon Store",
|
16
|
+
skills: [],
|
17
|
+
onMessage: async (context: XMTPContext) => {
|
18
|
+
const {
|
19
|
+
message: {
|
20
|
+
sender,
|
21
|
+
content: { skill },
|
22
|
+
},
|
23
|
+
agent,
|
24
|
+
} = context;
|
25
|
+
|
26
|
+
if (skill === "update") {
|
27
|
+
const page = await downloadPage();
|
28
|
+
fs.writeFileSync("src/prompt.md", page);
|
29
|
+
await context.reply("Notion DB updated");
|
30
|
+
}
|
31
|
+
|
32
|
+
let systemPrompt = await getPrompt();
|
33
|
+
let prompt = await replaceVariables(systemPrompt, sender.address, agent);
|
34
|
+
await agentReply(context, prompt);
|
35
|
+
},
|
36
|
+
};
|
37
|
+
|
38
|
+
run(agent);
|
39
|
+
|
40
|
+
async function getPrompt() {
|
41
|
+
return fs.readFileSync("src/prompt.md", "utf8");
|
42
|
+
}
|
43
|
+
async function setupFiles() {
|
44
|
+
const page = await downloadPage();
|
45
|
+
fs.writeFileSync("src/prompt.md", page);
|
46
|
+
console.log("Notion DB updated");
|
47
|
+
}
|
@@ -0,0 +1,60 @@
|
|
1
|
+
import { Client } from "@notionhq/client";
|
2
|
+
|
3
|
+
const notion = new Client({
|
4
|
+
auth: process.env.NOTION_API_KEY,
|
5
|
+
});
|
6
|
+
const poapsID = process.env.NOTION_POAP_DB;
|
7
|
+
const pageId = process.env.NOTION_PAGE_ID;
|
8
|
+
|
9
|
+
export async function updateDB() {
|
10
|
+
await notion.pages.update({
|
11
|
+
page_id: pageId as string,
|
12
|
+
properties: {
|
13
|
+
RSVP: {
|
14
|
+
type: "select",
|
15
|
+
select: {
|
16
|
+
name: "No",
|
17
|
+
},
|
18
|
+
},
|
19
|
+
},
|
20
|
+
});
|
21
|
+
}
|
22
|
+
export async function downloadPage() {
|
23
|
+
const blocks = await notion.blocks.children.list({
|
24
|
+
block_id: pageId as string,
|
25
|
+
});
|
26
|
+
const markdown = blocks.results
|
27
|
+
.map((block: any) => {
|
28
|
+
switch (block.type) {
|
29
|
+
case "paragraph":
|
30
|
+
return block.paragraph.rich_text
|
31
|
+
.map((text: any) => text.plain_text)
|
32
|
+
.join("");
|
33
|
+
case "heading_1":
|
34
|
+
return `# ${block.heading_1.rich_text
|
35
|
+
.map((text: any) => text.plain_text)
|
36
|
+
.join("")}`;
|
37
|
+
case "heading_2":
|
38
|
+
return `## ${block.heading_2.rich_text
|
39
|
+
.map((text: any) => text.plain_text)
|
40
|
+
.join("")}`;
|
41
|
+
case "heading_3":
|
42
|
+
return `### ${block.heading_3.rich_text
|
43
|
+
.map((text: any) => text.plain_text)
|
44
|
+
.join("")}`;
|
45
|
+
case "bulleted_list_item":
|
46
|
+
return `- ${block.bulleted_list_item.rich_text
|
47
|
+
.map((text: any) => text.plain_text)
|
48
|
+
.join("")}`;
|
49
|
+
case "numbered_list_item":
|
50
|
+
return `- ${block.numbered_list_item.rich_text
|
51
|
+
.map((text: any) => text.plain_text)
|
52
|
+
.join("")}`;
|
53
|
+
// Add more cases for other block types as needed
|
54
|
+
default:
|
55
|
+
return "";
|
56
|
+
}
|
57
|
+
})
|
58
|
+
.join("\n");
|
59
|
+
return markdown;
|
60
|
+
}
|
@@ -0,0 +1,27 @@
|
|
1
|
+
You are a helpful agent that lives inside a messaging app. You manage the general store from XMTP that delivers goodies, POAPs and testnet funds.
|
2
|
+
|
3
|
+
{rules}
|
4
|
+
|
5
|
+
{user_context}
|
6
|
+
|
7
|
+
{skills}
|
8
|
+
|
9
|
+
### Goodies
|
10
|
+
- When greeted for the first time, give the full menu.
|
11
|
+
- The user can select the option by number or name
|
12
|
+
- Once the option is selected confirm the order
|
13
|
+
## Response Scenarios:
|
14
|
+
- Welcome message:
|
15
|
+
Welcome to The General Store powered by ENS + XMTP, where web3 builders can get supplies, anytime, day or night.
|
16
|
+
Below is our menu. Let us know the number of the item you want, and it's yours. If it's a digital good, our bot will deliver those items right to your wallet.
|
17
|
+
- Chewing Gum
|
18
|
+
- TicTacs
|
19
|
+
- Deodorant
|
20
|
+
- RedBull
|
21
|
+
- Toothbrush
|
22
|
+
- Toothpaste
|
23
|
+
- XMTP Swag
|
24
|
+
- Testnet funds
|
25
|
+
- POAP
|
26
|
+
- Delivering goodies
|
27
|
+
Let me get your TicTacs... Your order is confirmed. Enjoy!
|
@@ -15,11 +15,8 @@ export const agent: Agent = {
|
|
15
15
|
name: "Playground Agent",
|
16
16
|
tag: "@bot",
|
17
17
|
description: "A playground agent with a lot of skills.",
|
18
|
-
skills: [
|
19
|
-
|
20
|
-
|
21
|
-
run(
|
22
|
-
async (context: XMTPContext) => {
|
18
|
+
skills: [web, cryptoPrice, search],
|
19
|
+
onMessage: async (context: XMTPContext) => {
|
23
20
|
const {
|
24
21
|
message: {
|
25
22
|
sender,
|
@@ -29,9 +26,13 @@ run(
|
|
29
26
|
} = context;
|
30
27
|
|
31
28
|
let prompt = await replaceVariables(systemPrompt, sender.address, agent);
|
32
|
-
//This is only used for to update the docs.
|
29
|
+
// This is only used for to update the docs.
|
33
30
|
fs.writeFileSync("example_prompt.md", prompt);
|
34
31
|
await agentReply(context, prompt);
|
35
32
|
},
|
36
|
-
|
37
|
-
|
33
|
+
config: {
|
34
|
+
experimental: true,
|
35
|
+
},
|
36
|
+
};
|
37
|
+
|
38
|
+
run(agent);
|
@@ -0,0 +1,9 @@
|
|
1
|
+
import { Vibe } from "@xmtp/message-kit";
|
2
|
+
|
3
|
+
export const chill: Vibe = {
|
4
|
+
name: "Chill",
|
5
|
+
description:
|
6
|
+
"A relaxed and easy-going personality, embodying the essence of tranquility and serenity. This vibe exudes a sense of calmness that soothes the soul and invites a peaceful atmosphere.",
|
7
|
+
tone: "calm and composed, like a gentle breeze on a warm summer day",
|
8
|
+
style: "laid-back, with an effortless grace that flows like a serene river",
|
9
|
+
};
|
@@ -0,0 +1,9 @@
|
|
1
|
+
import { Vibe } from "@xmtp/message-kit";
|
2
|
+
|
3
|
+
export const friendly: Vibe = {
|
4
|
+
name: "Friendly",
|
5
|
+
description:
|
6
|
+
"A warm and welcoming personality, radiating kindness and empathy. This vibe is like a comforting embrace, making everyone feel at home and valued.",
|
7
|
+
tone: "cheerful and uplifting, like the first rays of sunshine after a storm",
|
8
|
+
style: "approachable and open-hearted, with a smile that lights up the room",
|
9
|
+
};
|
@@ -0,0 +1,10 @@
|
|
1
|
+
import { Vibe } from "@xmtp/message-kit";
|
2
|
+
|
3
|
+
export const inquisitive: Vibe = {
|
4
|
+
name: "Inquisitive",
|
5
|
+
description:
|
6
|
+
"A curious and questioning nature, driven by an insatiable thirst for knowledge. This vibe is like a detective on a quest for truth, always seeking to uncover the mysteries of the world.",
|
7
|
+
tone: "curious and probing, like a cat exploring a new territory",
|
8
|
+
style:
|
9
|
+
"engaging and thought-provoking, with a knack for sparking lively discussions",
|
10
|
+
};
|
@@ -0,0 +1,10 @@
|
|
1
|
+
import { Vibe } from "@xmtp/message-kit";
|
2
|
+
|
3
|
+
export const playful: Vibe = {
|
4
|
+
name: "Playful",
|
5
|
+
description:
|
6
|
+
"A fun and light-hearted character, full of whimsy and joy. This vibe is like a child at play, bringing laughter and spontaneity to every moment.",
|
7
|
+
tone: "jovial and exuberant, like a carnival in full swing",
|
8
|
+
style:
|
9
|
+
"casual and carefree, with a dash of mischief and a twinkle in the eye",
|
10
|
+
};
|
@@ -0,0 +1,9 @@
|
|
1
|
+
import { Vibe } from "@xmtp/message-kit";
|
2
|
+
|
3
|
+
export const professional: Vibe = {
|
4
|
+
name: "Professional",
|
5
|
+
description:
|
6
|
+
"A formal and business-like demeanor, exuding confidence and competence. This vibe is like a seasoned diplomat, navigating complex situations with poise and precision.",
|
7
|
+
tone: "serious and authoritative, like a judge delivering a verdict",
|
8
|
+
style: "polished and refined, with an air of sophistication and elegance",
|
9
|
+
};
|
@@ -5,7 +5,6 @@ import {
|
|
5
5
|
XMTPContext,
|
6
6
|
Agent,
|
7
7
|
} from "@xmtp/message-kit";
|
8
|
-
|
9
8
|
import { systemPrompt } from "./prompt.js";
|
10
9
|
|
11
10
|
export const agent: Agent = {
|
@@ -13,13 +12,15 @@ export const agent: Agent = {
|
|
13
12
|
tag: "@bot",
|
14
13
|
description: "Use GPT to generate text responses.",
|
15
14
|
skills: [],
|
16
|
-
|
15
|
+
onMessage: async (context: XMTPContext) => {
|
16
|
+
const {
|
17
|
+
message: { sender },
|
18
|
+
agent,
|
19
|
+
} = context;
|
17
20
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
21
|
+
let prompt = await replaceVariables(systemPrompt, sender.address, agent);
|
22
|
+
await agentReply(context, prompt);
|
23
|
+
},
|
24
|
+
};
|
22
25
|
|
23
|
-
|
24
|
-
await agentReply(context, prompt);
|
25
|
-
});
|
26
|
+
run(agent);
|
@@ -2,5 +2,6 @@ KEY= # the private key of the wallet
|
|
2
2
|
TEST_ENCRYPTION_KEY= # a different private key for encryption
|
3
3
|
OPENAI_API_KEY= # the API key for OpenAI
|
4
4
|
REDIS_CONNECTION_STRING= # the connection to the toss database in Redis
|
5
|
+
COINBASE_APP_ID= # the app id for Coinbase
|
5
6
|
COINBASE_API_KEY_NAME= # the API key name for Coinbase
|
6
7
|
COINBASE_API_KEY_PRIVATE_KEY= # the private key for Coinbase
|
@@ -8,25 +8,22 @@ import {
|
|
8
8
|
|
9
9
|
import { systemPrompt } from "./prompt.js";
|
10
10
|
import { toss } from "./skills/toss.js";
|
11
|
-
import
|
11
|
+
import { waas } from "./skills/waas.js";
|
12
12
|
|
13
13
|
export const agent: Agent = {
|
14
14
|
name: "Toss Bot",
|
15
15
|
tag: "@toss",
|
16
16
|
description: "Create a coin toss.",
|
17
|
-
skills: [
|
18
|
-
|
19
|
-
|
20
|
-
run(
|
21
|
-
async (context: XMTPContext) => {
|
17
|
+
skills: [toss, waas],
|
18
|
+
onMessage: async (context: XMTPContext) => {
|
22
19
|
const {
|
23
20
|
message: { sender },
|
24
21
|
} = context;
|
25
22
|
|
26
23
|
let prompt = await replaceVariables(systemPrompt, sender.address, agent);
|
27
|
-
|
28
|
-
fs.writeFileSync("example_prompt.md", prompt);
|
24
|
+
|
29
25
|
await agentReply(context, prompt);
|
30
26
|
},
|
31
|
-
|
32
|
-
|
27
|
+
};
|
28
|
+
|
29
|
+
run(agent);
|
@@ -22,52 +22,12 @@ export const toss: Skill[] = [
|
|
22
22
|
},
|
23
23
|
},
|
24
24
|
},
|
25
|
-
{
|
26
|
-
skill: "create",
|
27
|
-
description: "Create an agent wallet.",
|
28
|
-
handler: handleDM,
|
29
|
-
examples: ["/create"],
|
30
|
-
},
|
31
|
-
{
|
32
|
-
skill: "fund",
|
33
|
-
description: "Fund your account.",
|
34
|
-
handler: handleDM,
|
35
|
-
examples: ["/fund 10"],
|
36
|
-
params: {
|
37
|
-
amount: {
|
38
|
-
type: "number",
|
39
|
-
},
|
40
|
-
},
|
41
|
-
},
|
42
|
-
{
|
43
|
-
skill: "withdraw",
|
44
|
-
description: "Withdraw funds from your account.",
|
45
|
-
handler: handleDM,
|
46
|
-
examples: ["/withdraw 10"],
|
47
|
-
params: {
|
48
|
-
amount: {
|
49
|
-
type: "number",
|
50
|
-
},
|
51
|
-
},
|
52
|
-
},
|
53
|
-
{
|
54
|
-
skill: "help",
|
55
|
-
description: "Get help with tossing.",
|
56
|
-
handler: handleDM,
|
57
|
-
examples: ["/help"],
|
58
|
-
},
|
59
25
|
{
|
60
26
|
skill: "cancel",
|
61
27
|
description: "Cancel a toss.",
|
62
28
|
handler: handleCancelToss,
|
63
29
|
examples: ["/cancel"],
|
64
30
|
},
|
65
|
-
{
|
66
|
-
skill: "balance",
|
67
|
-
description: "Check your balance.",
|
68
|
-
handler: handleDM,
|
69
|
-
examples: ["/balance"],
|
70
|
-
},
|
71
31
|
{
|
72
32
|
skill: "join",
|
73
33
|
description: "Join a toss.",
|
@@ -356,77 +316,3 @@ export async function handleTossStatus(context: XMTPContext) {
|
|
356
316
|
if (!tossData) return;
|
357
317
|
await context.reply(await generateTossStatusMessage(tossData));
|
358
318
|
}
|
359
|
-
|
360
|
-
export async function handleDM(context: XMTPContext) {
|
361
|
-
const {
|
362
|
-
message: {
|
363
|
-
content: {
|
364
|
-
skill,
|
365
|
-
params: { amount },
|
366
|
-
},
|
367
|
-
sender,
|
368
|
-
},
|
369
|
-
group,
|
370
|
-
walletService,
|
371
|
-
} = context;
|
372
|
-
if (group && skill == "help") {
|
373
|
-
await context.reply("Check your DM's");
|
374
|
-
await context.sendTo(DM_HELP_MESSAGE, [sender.address]);
|
375
|
-
return;
|
376
|
-
}
|
377
|
-
if (skill === "help") {
|
378
|
-
await context.send(DM_HELP_MESSAGE);
|
379
|
-
} else if (skill === "create") {
|
380
|
-
const walletExist = await walletService.getWallet(sender.address);
|
381
|
-
if (walletExist) {
|
382
|
-
await context.reply("You already have an agent wallet.");
|
383
|
-
return;
|
384
|
-
}
|
385
|
-
await walletService.createWallet(sender.address);
|
386
|
-
} else if (skill === "balance") {
|
387
|
-
const userWallet = await walletService.getWallet(sender.address);
|
388
|
-
|
389
|
-
context.sendTo(
|
390
|
-
`Your agent wallet for address is ${sender.address}\nBalance: $${await walletService.checkBalance(sender.address)}`,
|
391
|
-
[sender.address],
|
392
|
-
);
|
393
|
-
} else if (skill === "fund") {
|
394
|
-
const balance = await walletService.checkBalance(sender.address);
|
395
|
-
if (balance === 10) {
|
396
|
-
await context.reply("You have maxed out your funds.");
|
397
|
-
return;
|
398
|
-
} else if (amount) {
|
399
|
-
if (amount + balance <= 10) {
|
400
|
-
return walletService.requestFunds(Number(amount));
|
401
|
-
} else {
|
402
|
-
await context.send("Wrong amount. Max 10 USDC.");
|
403
|
-
return;
|
404
|
-
}
|
405
|
-
}
|
406
|
-
await context.reply(
|
407
|
-
`You have $${balance} in your account. You can fund up to $${10 - balance} more.`,
|
408
|
-
);
|
409
|
-
const options = Array.from({ length: Math.floor(10 - balance) }, (_, i) =>
|
410
|
-
(i + 1).toString(),
|
411
|
-
);
|
412
|
-
const response = await context.awaitResponse(
|
413
|
-
`Please specify the amount of USDC to prefund (1 to ${10 - balance}):`,
|
414
|
-
options,
|
415
|
-
);
|
416
|
-
return walletService.requestFunds(Number(response));
|
417
|
-
} else if (skill === "withdraw") {
|
418
|
-
const balance = await walletService.checkBalance(sender.address);
|
419
|
-
if (balance === 0) {
|
420
|
-
await context.reply("You have no funds to withdraw.");
|
421
|
-
return;
|
422
|
-
}
|
423
|
-
const options = Array.from({ length: Math.floor(balance) }, (_, i) =>
|
424
|
-
(i + 1).toString(),
|
425
|
-
);
|
426
|
-
const response = await context.awaitResponse(
|
427
|
-
`Please specify the amount of USDC to withdraw (1 to ${balance}):`,
|
428
|
-
options,
|
429
|
-
);
|
430
|
-
await walletService.withdrawFunds(Number(response));
|
431
|
-
}
|
432
|
-
}
|
@@ -0,0 +1,116 @@
|
|
1
|
+
import { Skill, XMTPContext, getUserInfo } from "@xmtp/message-kit";
|
2
|
+
import { DM_HELP_MESSAGE } from "../plugins/helpers.js";
|
3
|
+
|
4
|
+
export const waas: Skill[] = [
|
5
|
+
{
|
6
|
+
skill: "create",
|
7
|
+
description: "Create an agent wallet.",
|
8
|
+
handler: handleDM,
|
9
|
+
examples: ["/create"],
|
10
|
+
},
|
11
|
+
{
|
12
|
+
skill: "fund",
|
13
|
+
description: "Fund your account.",
|
14
|
+
handler: handleDM,
|
15
|
+
examples: ["/fund 10"],
|
16
|
+
params: {
|
17
|
+
amount: {
|
18
|
+
type: "number",
|
19
|
+
},
|
20
|
+
},
|
21
|
+
},
|
22
|
+
{
|
23
|
+
skill: "withdraw",
|
24
|
+
description: "Withdraw funds from your account.",
|
25
|
+
handler: handleDM,
|
26
|
+
examples: ["/withdraw 10"],
|
27
|
+
params: {
|
28
|
+
amount: {
|
29
|
+
type: "number",
|
30
|
+
},
|
31
|
+
},
|
32
|
+
},
|
33
|
+
{
|
34
|
+
skill: "help",
|
35
|
+
description: "Get help with tossing.",
|
36
|
+
handler: handleDM,
|
37
|
+
examples: ["/help"],
|
38
|
+
},
|
39
|
+
{
|
40
|
+
skill: "balance",
|
41
|
+
description: "Check your balance.",
|
42
|
+
handler: handleDM,
|
43
|
+
examples: ["/balance"],
|
44
|
+
},
|
45
|
+
];
|
46
|
+
|
47
|
+
export async function handleDM(context: XMTPContext) {
|
48
|
+
const {
|
49
|
+
message: {
|
50
|
+
content: {
|
51
|
+
skill,
|
52
|
+
params: { amount },
|
53
|
+
},
|
54
|
+
sender,
|
55
|
+
},
|
56
|
+
group,
|
57
|
+
walletService,
|
58
|
+
} = context;
|
59
|
+
if (group && skill == "help") {
|
60
|
+
await context.reply("Check your DM's");
|
61
|
+
await context.sendTo(DM_HELP_MESSAGE, [sender.address]);
|
62
|
+
return;
|
63
|
+
} else if (skill === "help") {
|
64
|
+
await context.send(DM_HELP_MESSAGE);
|
65
|
+
} else if (skill === "create") {
|
66
|
+
const walletExist = await walletService.getWallet(sender.address);
|
67
|
+
if (walletExist) {
|
68
|
+
await context.reply("You already have an agent wallet.");
|
69
|
+
return;
|
70
|
+
}
|
71
|
+
await walletService.createWallet(sender.address);
|
72
|
+
} else if (skill === "balance") {
|
73
|
+
context.sendTo(
|
74
|
+
`Your agent wallet for address is ${sender.address}\nBalance: $${await walletService.checkBalance(sender.address)}`,
|
75
|
+
[sender.address],
|
76
|
+
);
|
77
|
+
} else if (skill === "fund") {
|
78
|
+
const balance = await walletService.checkBalance(sender.address);
|
79
|
+
if (balance === 10) {
|
80
|
+
await context.reply("You have maxed out your funds.");
|
81
|
+
return;
|
82
|
+
} else if (amount) {
|
83
|
+
if (amount + balance <= 10) {
|
84
|
+
return walletService.requestFunds(Number(amount));
|
85
|
+
} else {
|
86
|
+
await context.send("Wrong amount. Max 10 USDC.");
|
87
|
+
return;
|
88
|
+
}
|
89
|
+
}
|
90
|
+
await context.reply(
|
91
|
+
`You have $${balance} in your account. You can fund up to $${10 - balance} more.`,
|
92
|
+
);
|
93
|
+
const options = Array.from({ length: Math.floor(10 - balance) }, (_, i) =>
|
94
|
+
(i + 1).toString(),
|
95
|
+
);
|
96
|
+
const response = await context.awaitResponse(
|
97
|
+
`Please specify the amount of USDC to prefund (1 to ${10 - balance}):`,
|
98
|
+
options,
|
99
|
+
);
|
100
|
+
return walletService.requestFunds(Number(response));
|
101
|
+
} else if (skill === "withdraw") {
|
102
|
+
const balance = await walletService.checkBalance(sender.address);
|
103
|
+
if (balance === 0) {
|
104
|
+
await context.reply("You have no funds to withdraw.");
|
105
|
+
return;
|
106
|
+
}
|
107
|
+
const options = Array.from({ length: Math.floor(balance) }, (_, i) =>
|
108
|
+
(i + 1).toString(),
|
109
|
+
);
|
110
|
+
const response = await context.awaitResponse(
|
111
|
+
`Please specify the amount of USDC to withdraw (1 to ${balance}):`,
|
112
|
+
options,
|
113
|
+
);
|
114
|
+
await walletService.withdrawFunds(Number(response));
|
115
|
+
}
|
116
|
+
}
|
package/templates.json
CHANGED
@@ -21,8 +21,8 @@
|
|
21
21
|
"author": "humanagent"
|
22
22
|
},
|
23
23
|
{
|
24
|
-
"href": "/templates/
|
25
|
-
"title": "
|
24
|
+
"href": "/templates/hackathon-store",
|
25
|
+
"title": "Hackathon Store",
|
26
26
|
"description": "All the goodies needed in a hackathon.",
|
27
27
|
"icon": "🏪",
|
28
28
|
"author": "humanagent"
|