create-message-kit 1.1.11 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
package/index.js CHANGED
@@ -85,7 +85,6 @@ async function gatherProjectInfo() {
85
85
  const templateOptions = [
86
86
  { value: "agent", label: "Web3 Agent" },
87
87
  { value: "gpt", label: "Simple Gpt" },
88
- { value: "group", label: "Group bot" },
89
88
  { value: "gated", label: "Gated Group" },
90
89
  ];
91
90
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-message-kit",
3
- "version": "1.1.11",
3
+ "version": "1.2.0",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -8,7 +8,8 @@
8
8
  "start": "node dist/index.js"
9
9
  },
10
10
  "dependencies": {
11
- "@xmtp/message-kit": "workspace:*"
11
+ "@xmtp/message-kit": "workspace:*",
12
+ "resend": "^4.0.1"
12
13
  },
13
14
  "devDependencies": {
14
15
  "@types/node": "^20.14.2",
@@ -35,23 +35,24 @@ export async function handler(context: XMTPContext) {
35
35
  wordle: "https://framedl.xyz",
36
36
  slot: "https://slot-machine-frame.vercel.app",
37
37
  };
38
- // Respond with the appropriate game URL or an error message
38
+ let returnText = "";
39
39
  switch (params.game) {
40
40
  case "wordle":
41
41
  case "slot":
42
42
  // Retrieve the URL for the requested game using a simplified variable assignment
43
43
  const gameUrl = gameUrls[params.game];
44
44
  // Send the URL for the requested game
45
- context.send(gameUrl);
45
+ returnText = gameUrl;
46
46
  break;
47
47
 
48
48
  case "help":
49
- context.send("Available games: \n/game wordle\n/game slot");
49
+ returnText = "Available games: \n/game wordle\n/game slot";
50
50
  break;
51
51
  default:
52
52
  // Inform the user about unrecognized skills and provide available options
53
- context.send(
54
- "Skill not recognized. Available games: wordle, slot, or help.",
55
- );
53
+ returnText =
54
+ "Skill not recognized. Available games: wordle, slot, or help.";
55
+ break;
56
56
  }
57
+ return { code: 200, message: returnText };
57
58
  }
@@ -35,13 +35,17 @@ export async function handler(context: XMTPContext) {
35
35
  message: "Domain not found.",
36
36
  };
37
37
  }
38
+ console.log(data);
38
39
  let message = `Domain information:\n\n`;
39
- message += `Address: ${data?.address}\n`;
40
- message += `Avatar URL: ${data?.ensInfo?.avatar}\n`;
41
- message += `Description: ${data?.ensInfo?.description}\n`;
42
- message += `ENS: ${data?.ensDomain}\n`;
43
- message += `Primary ENS: ${data?.ensInfo?.ens_primary}\n`;
44
- message += `GitHub: ${data?.ensInfo?.github}\n`;
40
+ message += `URL: https://app.ens.domains/${data?.ensDomain}\n`;
41
+ if (data?.address) message += `Address: ${data?.address}\n`;
42
+ if (data?.ensInfo?.avatar) message += `Avatar: ${data?.ensInfo?.avatar}\n`;
43
+ if (data?.ensInfo?.description)
44
+ message += `Description: ${data?.ensInfo?.description}\n`;
45
+ if (data?.ensInfo?.ens_primary)
46
+ message += `Primary ENS: ${data?.ensInfo?.ens_primary}\n`;
47
+ if (data?.ensInfo?.github) message += `GitHub: ${data?.ensInfo?.github}\n`;
48
+ if (data?.ensInfo?.twitter) message += `Twitter: ${data?.ensInfo?.twitter}\n`;
45
49
  message += `\n\nWould you like to tip the domain owner for getting there first 🤣?`;
46
50
  message = message.trim();
47
51
 
@@ -6,7 +6,7 @@ export const registerSkill: Skill[] = [
6
6
  skill: "/pay [amount] [token] [username]",
7
7
  examples: ["/pay 10 vitalik.eth"],
8
8
  description:
9
- "Send a specified amount of a cryptocurrency to a destination address.",
9
+ "Send a specified amount of a cryptocurrency to a destination address. \nWhen tipping, you can asume its 1 usdc.",
10
10
  handler: handler,
11
11
  params: {
12
12
  amount: {
@@ -35,6 +35,6 @@ export async function handler(context: XMTPContext) {
35
35
  }
36
36
  // Generate URL for the ens
37
37
  let url_ens = ensUrl + domain;
38
- context.send(`${url_ens}`);
39
38
  return { code: 200, message: `${url_ens}` };
40
39
  }
40
+
@@ -0,0 +1,58 @@
1
+ import { Resend } from 'resend';
2
+ import { XMTPContext } from "@xmtp/message-kit";
3
+ import type { Skill } from "@xmtp/message-kit";
4
+
5
+ const resend = new Resend(process.env.RESEND_API_KEY); // Replace with your Resend API key
6
+
7
+ export const registerSkill: Skill[] = [
8
+ {
9
+ skill: "/todo",
10
+ handler: handler,
11
+ examples: ["/todo"],
12
+ description: "Send a list of TODOs via email. Receives no parameters.",
13
+ params: {},
14
+ },
15
+ ];
16
+
17
+ export async function handler(context: XMTPContext) {
18
+ const {
19
+ message: {
20
+ content: { reply },
21
+ },
22
+ } = context;
23
+
24
+ let email = "";
25
+
26
+ while (true) {
27
+ const emailResponse = await context.awaitResponse("Please provide your email address to receive the TODO summary:");
28
+ email = emailResponse;
29
+
30
+ // Basic email validation
31
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
32
+ if (!emailRegex.test(email)) {
33
+ await context.send("Invalid email format. Please try again with a valid email address.");
34
+ continue;
35
+ }
36
+ break;
37
+ }
38
+
39
+ try {
40
+ let content={
41
+ from: 'onboarding@resend.dev',
42
+ to: email,
43
+ subject: 'Your TODO Summary from Converse',
44
+ html: `
45
+ <h1>Your TODO Summary</h1>
46
+ <p>${reply}</p>
47
+ `
48
+ }
49
+ console.log(content);
50
+ const response = await resend.emails.send(content);
51
+ console.log(response);
52
+
53
+ await context.send(`✅ Summary sent successfully to ${email}`);
54
+ } catch (error) {
55
+ await context.send("❌ Failed to send email. Please try again later.");
56
+ console.error('Error sending email:', error);
57
+ }
58
+ }
@@ -15,11 +15,11 @@ import { registerSkill as paySkill } from "./handlers/pay.js";
15
15
  import { registerSkill as resetSkill } from "./handlers/reset.js";
16
16
  import { registerSkill as tokenSkill } from "./handlers/token.js";
17
17
  import { registerSkill as gameSkill } from "./handlers/game.js";
18
+ import { registerSkill as todoSkill } from "./handlers/todo.js";
18
19
  import fs from "fs";
19
20
 
20
21
  export const frameUrl = "https://ens.steer.fun/";
21
22
  export const ensUrl = "https://app.ens.domains/";
22
- export const txpayUrl = "https://txpay.vercel.app";
23
23
 
24
24
  // [!region skills]
25
25
  export const agent: Agent = {
@@ -36,11 +36,12 @@ export const agent: Agent = {
36
36
  ...paySkill,
37
37
  ...tokenSkill,
38
38
  ...gameSkill,
39
+ ...todoSkill,
39
40
  ],
40
41
  };
41
42
  // [!endregion skills]
42
43
 
43
- // [!region run]
44
+ // [!region run1]
44
45
  run(
45
46
  async (context: XMTPContext) => {
46
47
  const {
@@ -49,11 +50,13 @@ run(
49
50
  } = context;
50
51
 
51
52
  let prompt = await replaceVariables(systemPrompt, sender.address, agent);
52
-
53
+ // [!region run1]
54
+ //This is only used for to update the docs.
53
55
  fs.writeFileSync("example_prompt.md", prompt);
56
+ // [!region run2]
54
57
  await agentReply(context, prompt);
55
58
  },
56
59
  { agent },
57
60
  );
58
61
 
59
- // [!endregion run]
62
+ // [!endregion run2]
@@ -7,46 +7,14 @@ Your are helpful and playful web3 agent called {agent_name} that lives inside a
7
7
 
8
8
  {skills}
9
9
 
10
- ## Response Scenarios:
11
-
12
- 1. When greeting or when the user asks for an ENS domain, check if the user does not have an ENS domain:
13
- Hey {name}! It looks like you don't have an ENS domain yet!
14
- Let me start by checking your Converse username with the .eth suffix
15
- /check localdev6.eth
16
- 2. If the user has an ENS domain:
17
- I'll help you get your ENS domain.
18
- Let's start by checking your ENS domain. Give me a moment.
19
- /check [domain]
20
- 3. Check if the ENS domain is available:
21
- Hello! I'll help you get your domain.
22
- Let's start by checking your ENS domain. Give me a moment.
23
- /check [domain]
24
- 4. If the ENS domain is available:
25
- Looks like [domain] is available! Here you can register it:
26
- /register [domain]
27
- Or I can suggest some cool alternatives? Let me know!
28
- 5. If the ENS domain is already registered, suggest 5 cool alternatives:
29
- Looks like [domain] is already registered!
30
- What about these cool alternatives?
31
- /cool [domain]
32
- 6. If the user wants to register an ENS domain:
33
- Looks like [domain] is available! Let me help you register it.
34
- /register [domain]
35
- 7. If the user wants to directly tip the ENS domain owner:
36
- Here is the URL to send the tip:
37
- /pay 1 usdc [address]
38
- 8. If the user wants to get information about the ENS domain:
39
- Hello! I'll help you get info about [domain].
40
- Give me a moment.
41
- /info [domain]
42
- 9. If the user wants to renew their domain:
43
- Hello! I'll help you get your ENS domain.
44
- Let's start by checking your ENS domain. Give me a moment.
45
- /renew [domain]
46
- 10. If the user wants cool suggestions about a domain:
47
- Here are some cool suggestions for your domain.
48
- /cool [domain]
49
-
50
- ## Most common bugs
51
- 1. Some times you will say something like: "Looks like vitalik.eth is registered! What about these cool alternatives?" But you forgot to add the command at the end of the message.
10
+ ## Common Issues
11
+ 1. Missing commands in responses
12
+ **Issue**: Sometimes responses about registered domains are sent without the required command.
13
+ **Example**:
14
+ Incorrect:
15
+ > "Looks like vitalik.eth is registered! What about these cool alternatives?"
16
+
17
+ Correct:
18
+ > "Looks like vitalik.eth is registered! What about these cool alternatives?
19
+ > /cool vitalik.eth"
52
20
  `;
@@ -2,6 +2,7 @@ import type { Agent } from "@xmtp/message-kit";
2
2
 
3
3
  export const agent: Agent = {
4
4
  name: "Group Id",
5
+ tag: "@bot",
5
6
  description: "Create and get group id.",
6
7
  skills: [
7
8
  {
@@ -19,6 +19,6 @@ run(async (context: XMTPContext) => {
19
19
  message: { sender },
20
20
  } = context;
21
21
 
22
- let prompt = await replaceVariables(systemPrompt, sender.address, skills);
22
+ let prompt = await replaceVariables(systemPrompt, sender.address, agent);
23
23
  await agentReply(context, prompt);
24
24
  });
@@ -1,2 +0,0 @@
1
- KEY= # the private key of the agent wallet
2
- OPENAI_API_KEY= # openai api key
@@ -1,4 +0,0 @@
1
- compressionLevel: mixed
2
- enableGlobalCache: false
3
- enableTelemetry: false
4
- nodeLinker: node-modules
@@ -1,20 +0,0 @@
1
- {
2
- "name": "group",
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
- "@xmtp/message-kit": "workspace:*"
12
- },
13
- "devDependencies": {
14
- "@types/node": "^20.14.2",
15
- "typescript": "^5.4.5"
16
- },
17
- "engines": {
18
- "node": ">=20"
19
- }
20
- }
@@ -1,57 +0,0 @@
1
- import { XMTPContext } from "@xmtp/message-kit";
2
- import type { Skill } from "@xmtp/message-kit";
3
-
4
- export const registerSkill: Skill[] = [
5
- {
6
- skill: "/game [game]",
7
- handler: handler,
8
- description: "Play a game.",
9
- examples: ["/game wordle", "/game slot", "/game help"],
10
- params: {
11
- game: {
12
- default: "",
13
- type: "string",
14
- values: ["wordle", "slot", "help"],
15
- },
16
- },
17
- },
18
- ];
19
-
20
- export async function handler(context: XMTPContext) {
21
- const {
22
- message: {
23
- content: { skill, params, text },
24
- },
25
- } = context;
26
- if (!skill) {
27
- if (text === "🔎" || text === "🔍") {
28
- // Send the URL for the requested game
29
- context.reply("https://framedl.xyz/");
30
- }
31
- return;
32
- }
33
- // URLs for each game type
34
- const gameUrls: { [key: string]: string } = {
35
- wordle: "https://framedl.xyz",
36
- slot: "https://slot-machine-frame.vercel.app",
37
- };
38
- // Respond with the appropriate game URL or an error message
39
- switch (params.game) {
40
- case "wordle":
41
- case "slot":
42
- // Retrieve the URL for the requested game using a simplified variable assignment
43
- const gameUrl = gameUrls[params.game];
44
- // Send the URL for the requested game
45
- context.send(gameUrl);
46
- break;
47
-
48
- case "help":
49
- context.send("Available games: \n/game wordle\n/game slot");
50
- break;
51
- default:
52
- // Inform the user about unrecognized skills and provide available options
53
- context.send(
54
- "Skill not recognized. Available games: wordle, slot, or help.",
55
- );
56
- }
57
- }
@@ -1,46 +0,0 @@
1
- import { XMTPContext } from "@xmtp/message-kit";
2
-
3
- import type { Skill } from "@xmtp/message-kit";
4
-
5
- export const registerSkill: Skill[] = [
6
- {
7
- skill: "/help",
8
- examples: ["/help"],
9
- handler: handleHelp,
10
- description: "Get help with the bot.",
11
- params: {},
12
- },
13
- {
14
- skill: "/id",
15
- examples: ["/id"],
16
- handler: handleHelp,
17
- description: "Get the group ID.",
18
- params: {},
19
- },
20
- ];
21
-
22
- export async function handleHelp(context: XMTPContext) {
23
- const {
24
- message: {
25
- content: { skill },
26
- },
27
- group,
28
- agent,
29
- } = context;
30
-
31
- if (skill == "help") {
32
- const intro =
33
- "Available experiences:\n" +
34
- agent?.skills
35
- .map((skill) => `${skill.skill} - ${skill.description}`)
36
- .join("\n") +
37
- "\nUse these skills to interact with specific apps.";
38
- context.send(intro);
39
- } else if (skill == "id") {
40
- if (!group?.id) {
41
- context.send("This skill only works in group chats.");
42
- return;
43
- }
44
- context.send(group?.id);
45
- }
46
- }
@@ -1,38 +0,0 @@
1
- import { XMTPContext } from "@xmtp/message-kit";
2
- import type { Skill } from "@xmtp/message-kit";
3
-
4
- export const registerSkill: Skill[] = [
5
- {
6
- skill: "/pay [amount] [token] [username]",
7
- examples: ["/pay 10 vitalik.eth"],
8
- description:
9
- "Send a specified amount of a cryptocurrency to a destination address.",
10
- handler: handler,
11
- params: {
12
- amount: {
13
- default: 10,
14
- type: "number",
15
- },
16
- token: {
17
- default: "usdc",
18
- type: "string",
19
- values: ["eth", "dai", "usdc", "degen"], // Accepted tokens
20
- },
21
- username: {
22
- default: "",
23
- type: "username",
24
- },
25
- },
26
- },
27
- ];
28
- export async function handler(context: XMTPContext) {
29
- const {
30
- message: {
31
- content: {
32
- params: { address },
33
- },
34
- },
35
- } = context;
36
-
37
- await context.requestPayment(1, "USDC", address);
38
- }
@@ -1,60 +0,0 @@
1
- import { getUserInfo, AbstractedMember, XMTPContext } from "@xmtp/message-kit";
2
- import type { Skill } from "@xmtp/message-kit";
3
-
4
- export const registerSkill: Skill[] = [
5
- {
6
- skill: "/tip [usernames] [amount] [token]",
7
- examples: ["/tip @vitalik 10 usdc"],
8
- description: "Tip users in a specified token.",
9
- handler: handleTipping,
10
- params: {
11
- username: {
12
- default: "",
13
- plural: true,
14
- type: "username",
15
- },
16
- amount: {
17
- default: 10,
18
- type: "number",
19
- },
20
- token: {
21
- default: "usdc",
22
- type: "string",
23
- values: ["eth", "dai", "usdc", "degen"],
24
- },
25
- },
26
- },
27
- ];
28
-
29
- export async function handleTipping(context: XMTPContext) {
30
- const {
31
- message: {
32
- content: {
33
- skill,
34
- params: { amount, username },
35
- },
36
- sender,
37
- },
38
- } = context;
39
- let receivers: AbstractedMember[] = [];
40
-
41
- receivers = await Promise.all(
42
- username.map((username: string) => getUserInfo(username)),
43
- );
44
-
45
- if (!sender || receivers.length === 0 || amount === 0) {
46
- context.reply("Sender or receiver or amount not found.");
47
- }
48
- const receiverAddresses = receivers.map((receiver) => receiver.address);
49
-
50
- context.sendTo(
51
- `You received ${amount} tokens from ${sender.address}.`,
52
- receiverAddresses,
53
- );
54
-
55
- // Notify sender of the transaction details
56
- context.sendTo(
57
- `You sent ${amount * receiverAddresses.length} tokens in total.`,
58
- [sender.address],
59
- );
60
- }
@@ -1,32 +0,0 @@
1
- import {
2
- run,
3
- agentReply,
4
- XMTPContext,
5
- replaceVariables,
6
- Agent,
7
- } from "@xmtp/message-kit";
8
- import { registerSkill as tippingSkill } from "./handlers/tipping.js";
9
- import { registerSkill as paymentSkill } from "./handlers/pay.js";
10
- import { registerSkill as gameSkill } from "./handlers/game.js";
11
- import { registerSkill as helperSkill } from "./handlers/helpers.js";
12
- import { systemPrompt } from "./prompt.js";
13
-
14
- export const agent: Agent = {
15
- name: "Group bot",
16
- tag: "@bot",
17
- description: "Group agent for tipping payments, games and more.",
18
- skills: [...tippingSkill, ...paymentSkill, ...gameSkill, ...helperSkill],
19
- };
20
-
21
- run(
22
- async (context: XMTPContext) => {
23
- const {
24
- message: { sender },
25
- agent,
26
- } = context;
27
-
28
- let prompt = await replaceVariables(systemPrompt, sender.address, agent);
29
- await agentReply(context, prompt);
30
- },
31
- { agent },
32
- );
@@ -1,33 +0,0 @@
1
- export const systemPrompt = `
2
- {persona}
3
-
4
- {rules}
5
-
6
- {user_context}
7
-
8
- {skills}
9
-
10
- ## Response Scenarios
11
-
12
- 1. If the user wants to play a game suggest direcly a game like wordle:
13
- Let's play wordle!
14
- /game wordle
15
-
16
- 2. When user wants to pay a specific token:
17
- I'll help you pay 1 USDC to 0x123...
18
- /pay 1 [token] 0x123456789...
19
- *This will return a url to pay
20
-
21
- 3. If the user wants to pay a eth domain:
22
- I'll help you pay 1 USDC to vitalik.eth
23
- Be aware that this only works on mobile with a installed wallet on Base network
24
- /pay 1 vitalik.eth
25
- *This will return a url to pay
26
-
27
- 4. If the user wants to pay a username:
28
- I'll help you pay 1 USDC to @fabri
29
- Be aware that this only works on mobile with a installed wallet on Base network
30
- /pay 1 @fabri
31
- *This will return a url to pay
32
-
33
- `;