create-message-kit 1.2.22 → 1.2.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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"