create-message-kit 1.1.11 → 1.2.2

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/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.2",
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,63 @@
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: "Summarize your TODOs and send an email with the summary. 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
+ let intents=2
27
+ while (intents>0) {
28
+ const emailResponse = await context.awaitResponse("Please provide your email address to receive the TODO summary:");
29
+ email = emailResponse;
30
+
31
+ // Basic email validation
32
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
33
+ if (!emailRegex.test(email)) {
34
+ await context.send("Invalid email format. Please try again with a valid email address.");
35
+ intents--;
36
+ continue;
37
+ }
38
+ break;
39
+ }
40
+ if(intents==0){
41
+ await context.send("I couldn't get your email address. Please try again later.");
42
+ return;
43
+ }
44
+ try {
45
+ let content={
46
+ from: 'onboarding@resend.dev',
47
+ to: email,
48
+ subject: 'Your TODO Summary from Converse',
49
+ html: `
50
+ <h1>Your TODO Summary</h1>
51
+ <p>${reply}</p>
52
+ `
53
+ }
54
+ console.log(content);
55
+ // const response = await resend.emails.send(content);
56
+ // console.log(response);
57
+
58
+ await context.send(`✅ Summary sent successfully to ${email}`);
59
+ } catch (error) {
60
+ await context.send("❌ Failed to send email. Please try again later.");
61
+ console.error('Error sending email:', error);
62
+ }
63
+ }
@@ -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
- { agent },
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 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
  `;
@@ -42,7 +42,7 @@ async function createGroup(
42
42
  clientAddress: string,
43
43
  ) {
44
44
  let senderInboxId = "";
45
- const group = await client?.conversations.newConversation([
45
+ const group = await client?.conversations.newGroup([
46
46
  senderAddress,
47
47
  clientAddress,
48
48
  ]);
@@ -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
- `;