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 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.22";
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
- // Check if running through npm init
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-message-kit",
3
- "version": "1.2.22",
3
+ "version": "1.2.23",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -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: [...swapSkill, ...mintSkill, ...dripSkill, ...paySkill],
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
- { agent }
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
- ...checkDomain,
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
- { agent },
51
- );
31
+ };
52
32
 
53
- // [!endregion run2]
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
- if (
52
- await context.isOnXMTP(context.client, context.v2client, sender?.address)
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: [...faucet],
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
- // [!endregion run1]
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
- { agent },
37
- );
38
-
39
- // [!endregion run2]
27
+ };
28
+ run(agent);
@@ -12,6 +12,6 @@ export const agent: Agent = {
12
12
  name: "Gated Group Creator Agent",
13
13
  tag: "@bot",
14
14
  description: "A gated group creator agent.",
15
- skills: [...gated],
15
+ skills: [gated],
16
16
  };
17
- run(async (context: XMTPContext) => {}, { agent });
17
+ run(agent);
@@ -1,8 +1,16 @@
1
- import { run } from "@xmtp/message-kit";
1
+ import { run, Agent } from "@xmtp/message-kit";
2
2
 
3
- run(async (context) => {
4
- const { group } = context;
5
- if (!group) {
6
- await context.send(`gm`);
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,6 @@
1
+ TEST_ENCRYPTION_KEY= # test encryption key
2
+ KEY= # key of xmtp bot
3
+ NOTION_API_KEY= # notion api key
4
+ NOTION_PAGE_ID= # notion page id
5
+ OPENAI_API_KEY= # openai api key
6
+ REDIS_CONNECTION_STRING= # redis connection string
@@ -0,0 +1,9 @@
1
+ compressionLevel: mixed
2
+
3
+ enableGlobalCache: false
4
+
5
+ enableTelemetry: false
6
+
7
+ nodeLinker: node-modules
8
+
9
+ yarnPath: .yarn/releases/yarn-4.5.1.cjs
@@ -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: [...web, ...cryptoPrice, ...search],
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
- { agent, experimental: true },
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
- run(async (context: XMTPContext) => {
19
- const {
20
- message: { sender },
21
- } = context;
21
+ let prompt = await replaceVariables(systemPrompt, sender.address, agent);
22
+ await agentReply(context, prompt);
23
+ },
24
+ };
22
25
 
23
- let prompt = await replaceVariables(systemPrompt, sender.address, agent);
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 fs from "fs";
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: [...toss],
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
- //This is only used for to update the docs.
28
- fs.writeFileSync("example_prompt.md", prompt);
24
+
29
25
  await agentReply(context, prompt);
30
26
  },
31
- { agent },
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/thegeneralstore",
25
- "title": "The General Store",
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"