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 +0 -1
- package/package.json +1 -1
- package/templates/agent/package.json +2 -1
- package/templates/agent/src/handlers/game.ts +7 -6
- package/templates/agent/src/handlers/info.ts +10 -6
- package/templates/agent/src/handlers/pay.ts +1 -1
- package/templates/agent/src/handlers/register.ts +1 -1
- package/templates/agent/src/handlers/todo.ts +63 -0
- package/templates/agent/src/index.ts +8 -5
- package/templates/agent/src/prompt.ts +10 -42
- package/templates/gated/src/index.ts +1 -1
- package/templates/gated/src/skills.ts +1 -0
- package/templates/gpt/src/index.ts +1 -1
- package/templates/group/.env.example +0 -2
- package/templates/group/.yarnrc.yml +0 -4
- package/templates/group/package.json +0 -20
- package/templates/group/src/handlers/game.ts +0 -57
- package/templates/group/src/handlers/helpers.ts +0 -46
- package/templates/group/src/handlers/pay.ts +0 -38
- package/templates/group/src/handlers/tipping.ts +0 -60
- package/templates/group/src/index.ts +0 -32
- package/templates/group/src/prompt.ts +0 -33
package/index.js
CHANGED
package/package.json
CHANGED
@@ -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
|
-
|
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
|
-
|
45
|
+
returnText = gameUrl;
|
46
46
|
break;
|
47
47
|
|
48
48
|
case "help":
|
49
|
-
|
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
|
-
|
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 += `
|
40
|
-
message += `
|
41
|
-
message += `
|
42
|
-
|
43
|
-
|
44
|
-
|
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: {
|
@@ -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
|
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
|
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
|
-
##
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
/
|
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
|
`;
|
@@ -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,
|
22
|
+
let prompt = await replaceVariables(systemPrompt, sender.address, agent);
|
23
23
|
await agentReply(context, prompt);
|
24
24
|
});
|
@@ -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
|
-
`;
|