create-message-kit 1.1.9-beta.1 → 1.1.9-beta.2

Sign up to get free protection for your applications and to get access to all the features.
package/index.js CHANGED
@@ -89,10 +89,10 @@ async function addPackagejson(destDir, name, pkgManager) {
89
89
  };
90
90
 
91
91
  if (pkgManager.includes("yarn")) {
92
- //packageTemplate.packageManager = `${pkgManager}`;
93
- // Add .yarnrc.yml to disable PnP mode
92
+ packageTemplate.packageManager = `yarn@4.5.1`;
94
93
  }
95
94
 
95
+ // Add .yarnrc.yml just in caseto disable PnP mode
96
96
  fs.writeFileSync(
97
97
  resolve(destDir, ".yarnrc.yml"),
98
98
  "nodeLinker: node-modules\n",
@@ -105,10 +105,9 @@ async function addPackagejson(destDir, name, pkgManager) {
105
105
 
106
106
  async function gatherProjectInfo() {
107
107
  const templateOptions = [
108
- { value: "gpt", label: "GPT" },
108
+ { value: "gpt", label: "Simple Gpt" },
109
109
  { value: "agent", label: "Agent" },
110
110
  { value: "group", label: "Group" },
111
- { value: "ens-agent-pro", label: "Ens Agent Pro" },
112
111
  ];
113
112
 
114
113
  const templateType = await select({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-message-kit",
3
- "version": "1.1.9-beta.1",
3
+ "version": "1.1.9-beta.2",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -30,7 +30,7 @@
30
30
  "@types/node": "^20.14.2",
31
31
  "prettier": "^3.3.1"
32
32
  },
33
- "packageManager": "yarn@4.2.2",
33
+ "packageManager": "yarn@4.5.1",
34
34
  "engines": {
35
35
  "node": ">=20"
36
36
  },
@@ -0,0 +1,43 @@
1
+ import { ensUrl } from "../index.js";
2
+ import { XMTPContext, getUserInfo } from "@xmtp/message-kit";
3
+
4
+ import type { skillAction } from "@xmtp/message-kit";
5
+
6
+ export const registerSkill: skillAction[] = [
7
+ {
8
+ skill: "/check [domain]",
9
+ handler: handleCheck,
10
+ examples: ["/check vitalik.eth", "/check fabri.base.eth"],
11
+ description: "Check if a domain is available.",
12
+ params: {
13
+ domain: {
14
+ type: "string",
15
+ },
16
+ },
17
+ },
18
+ ];
19
+ export async function handleCheck(context: XMTPContext) {
20
+ const {
21
+ message: {
22
+ content: {
23
+ params: { domain },
24
+ },
25
+ },
26
+ } = context;
27
+
28
+ const data = await getUserInfo(domain);
29
+ if (!data?.address) {
30
+ let message = `Looks like ${domain} is available! Here you can register it: ${ensUrl}${domain} or would you like to see some cool alternatives?`;
31
+ return {
32
+ code: 200,
33
+ message,
34
+ };
35
+ } else {
36
+ let message = `Looks like ${domain} is already registered!`;
37
+ await context.executeSkill("/cool " + domain);
38
+ return {
39
+ code: 404,
40
+ message,
41
+ };
42
+ }
43
+ }
@@ -0,0 +1,52 @@
1
+ import { XMTPContext } from "@xmtp/message-kit";
2
+
3
+ import type { skillAction } from "@xmtp/message-kit";
4
+
5
+ export const registerSkill: skillAction[] = [
6
+ {
7
+ skill: "/cool [domain]",
8
+ examples: ["/cool vitalik.eth"],
9
+ handler: handleCool,
10
+ description: "Get cool alternatives for a .eth domain.",
11
+ params: {
12
+ domain: {
13
+ type: "string",
14
+ },
15
+ },
16
+ },
17
+ ];
18
+ export async function handleCool(context: XMTPContext) {
19
+ const {
20
+ message: {
21
+ content: {
22
+ params: { domain },
23
+ },
24
+ },
25
+ } = context;
26
+ //What about these cool alternatives?\
27
+ return {
28
+ code: 200,
29
+ message: `${generateCoolAlternatives(domain)}`,
30
+ };
31
+ }
32
+
33
+ export const generateCoolAlternatives = (domain: string) => {
34
+ const suffixes = ["lfg", "cool", "degen", "moon", "base", "gm"];
35
+ const alternatives = [];
36
+ for (let i = 0; i < 5; i++) {
37
+ const randomPosition = Math.random() < 0.5;
38
+ const baseDomain = domain.replace(/\.eth$/, ""); // Remove any existing .eth suffix
39
+ alternatives.push(
40
+ randomPosition
41
+ ? `${suffixes[i]}${baseDomain}.eth`
42
+ : `${baseDomain}${suffixes[i]}.eth`,
43
+ );
44
+ }
45
+
46
+ const cool_alternativesFormat = alternatives
47
+ .map(
48
+ (alternative: string, index: number) => `${index + 1}. ${alternative} ✨`,
49
+ )
50
+ .join("\n");
51
+ return cool_alternativesFormat;
52
+ };
@@ -0,0 +1,65 @@
1
+ import { ensUrl } from "../index.js";
2
+ import { XMTPContext, getUserInfo, isOnXMTP } from "@xmtp/message-kit";
3
+
4
+ import type { skillAction } from "@xmtp/message-kit";
5
+
6
+ export const registerSkill: skillAction[] = [
7
+ {
8
+ skill: "/info [domain]",
9
+ handler: handleInfo,
10
+ description:
11
+ "Get detailed information about an ENS domain including owner, expiry date, and resolver.",
12
+ examples: ["/info nick.eth"],
13
+ params: {
14
+ domain: {
15
+ type: "string",
16
+ },
17
+ },
18
+ },
19
+ ];
20
+
21
+ export async function handleInfo(context: XMTPContext) {
22
+ const {
23
+ message: {
24
+ sender,
25
+ content: {
26
+ params: { domain },
27
+ },
28
+ },
29
+ } = context;
30
+
31
+ const data = await getUserInfo(domain);
32
+ if (!data?.ensDomain) {
33
+ return {
34
+ code: 404,
35
+ message: "Domain not found.",
36
+ };
37
+ }
38
+
39
+ const formattedData = {
40
+ Address: data?.address,
41
+ "Avatar URL": data?.ensInfo?.avatar,
42
+ Description: data?.ensInfo?.description,
43
+ ENS: data?.ensDomain,
44
+ "Primary ENS": data?.ensInfo?.ens_primary,
45
+ GitHub: data?.ensInfo?.github,
46
+ Resolver: data?.ensInfo?.resolverAddress,
47
+ Twitter: data?.ensInfo?.twitter,
48
+ URL: `${ensUrl}${domain}`,
49
+ };
50
+
51
+ let message = "Domain information:\n\n";
52
+ for (const [key, value] of Object.entries(formattedData)) {
53
+ if (value) {
54
+ message += `${key}: ${value}\n`;
55
+ }
56
+ }
57
+ message += `\n\nWould you like to tip the domain owner for getting there first 🤣?`;
58
+ message = message.trim();
59
+ if (await isOnXMTP(context.client, context.v2client, sender?.address)) {
60
+ await context.send(
61
+ `Ah, this domains is in XMTP, you can message it directly: https://converse.xyz/dm/${domain}`,
62
+ );
63
+ }
64
+ return { code: 200, message };
65
+ }
@@ -0,0 +1,40 @@
1
+ import { ensUrl } from "../index.js";
2
+ import { XMTPContext } from "@xmtp/message-kit";
3
+
4
+ import type { skillAction } from "@xmtp/message-kit";
5
+
6
+ export const registerSkill: skillAction[] = [
7
+ {
8
+ skill: "/register [domain]",
9
+ handler: handleRegister,
10
+ description:
11
+ "Register a new ENS domain. Returns a URL to complete the registration process.",
12
+ examples: ["/register vitalik.eth"],
13
+ params: {
14
+ domain: {
15
+ type: "string",
16
+ },
17
+ },
18
+ },
19
+ ];
20
+
21
+ export async function handleRegister(context: XMTPContext) {
22
+ const {
23
+ message: {
24
+ content: {
25
+ params: { domain },
26
+ },
27
+ },
28
+ } = context;
29
+
30
+ if (!domain) {
31
+ return {
32
+ code: 400,
33
+ message: "Missing required parameters. Please provide domain.",
34
+ };
35
+ }
36
+ // Generate URL for the ens
37
+ let url_ens = ensUrl + domain;
38
+ context.send(`${url_ens}`);
39
+ return { code: 200, message: `${url_ens}` };
40
+ }
@@ -0,0 +1,52 @@
1
+ import { frameUrl } from "../index.js";
2
+ import { getUserInfo, XMTPContext } from "@xmtp/message-kit";
3
+
4
+ import type { skillAction } from "@xmtp/message-kit";
5
+
6
+ export const registerSkill: skillAction[] = [
7
+ {
8
+ skill: "/renew [domain]",
9
+ handler: handleRenew,
10
+ description:
11
+ "Extend the registration period of your ENS domain. Returns a URL to complete the renewal.",
12
+ examples: ["/renew fabri.base.eth"],
13
+ params: {
14
+ domain: {
15
+ type: "string",
16
+ },
17
+ },
18
+ },
19
+ ];
20
+
21
+ export async function handleRenew(context: XMTPContext) {
22
+ const {
23
+ message: {
24
+ sender,
25
+ content: {
26
+ params: { domain },
27
+ },
28
+ },
29
+ } = context;
30
+
31
+ // Check if the user holds the domain
32
+ if (!domain) {
33
+ return {
34
+ code: 400,
35
+ message: "Missing required parameters. Please provide domain.",
36
+ };
37
+ }
38
+
39
+ const data = await getUserInfo(domain);
40
+
41
+ if (!data?.address || data?.address !== sender?.address) {
42
+ return {
43
+ code: 403,
44
+ message:
45
+ "Looks like this domain is not registered to you. Only the owner can renew it.",
46
+ };
47
+ }
48
+
49
+ // Generate URL for the ens
50
+ let url_ens = frameUrl + "frames/manage?name=" + domain;
51
+ return { code: 200, message: `${url_ens}` };
52
+ }
@@ -0,0 +1,19 @@
1
+ import { clearInfoCache, clearMemory } from "@xmtp/message-kit";
2
+ import { XMTPContext } from "@xmtp/message-kit";
3
+
4
+ import type { skillAction } from "@xmtp/message-kit";
5
+
6
+ export const registerSkill: skillAction[] = [
7
+ {
8
+ skill: "/reset",
9
+ examples: ["/reset"],
10
+ handler: handleReset,
11
+ description: "Reset the conversation.",
12
+ params: {},
13
+ },
14
+ ];
15
+ export async function handleReset(context: XMTPContext) {
16
+ clearMemory();
17
+ clearInfoCache();
18
+ return { code: 200, message: "Conversation reset." };
19
+ }
@@ -0,0 +1,42 @@
1
+ import { txpayUrl } from "../index.js";
2
+ import { XMTPContext, getUserInfo } from "@xmtp/message-kit";
3
+
4
+ import type { skillAction } from "@xmtp/message-kit";
5
+
6
+ export const registerSkill: skillAction[] = [
7
+ {
8
+ skill: "/tip [address]",
9
+ description: "Show a URL for tipping a domain owner.",
10
+ handler: handleTip,
11
+ examples: ["/tip 0x1234567890123456789012345678901234567890"],
12
+ params: {
13
+ address: {
14
+ type: "string",
15
+ },
16
+ },
17
+ },
18
+ ];
19
+ export async function handleTip(context: XMTPContext) {
20
+ const {
21
+ message: {
22
+ content: {
23
+ params: { address },
24
+ },
25
+ },
26
+ } = context;
27
+
28
+ if (!address) {
29
+ return {
30
+ code: 400,
31
+ message: "Please provide an address to tip.",
32
+ };
33
+ }
34
+ const data = await getUserInfo(address);
35
+
36
+ let sendUrl = `${txpayUrl}/?&amount=1&token=USDC&receiver=${address}`;
37
+
38
+ return {
39
+ code: 200,
40
+ message: sendUrl,
41
+ };
42
+ }
@@ -1,55 +1,50 @@
1
- import { run, HandlerContext } from "@xmtp/message-kit";
2
- import { agentRun } from "@xmtp/message-kit";
3
- import { skills } from "./skills.js";
4
- import { defaultPromptTemplate } from "@xmtp/message-kit";
5
-
6
- export async function agent_prompt(senderAddress: string) {
7
- let fineTuning = `
8
- ## Example responses:
9
-
10
- 1. Check if the user does not have a ENS domain
11
- Hey {PREFERRED_NAME}! it looks like you don't have a ENS domain yet! \n\Let me start by checking your Converse username with the .eth suffix\n/check {CONVERSE_USERNAME}.eth
12
-
13
- 2. If the user has a ENS domain
14
- Hello {PREFERRED_NAME} ! I'll help you get your ENS domain.\n Let's start by checking your ENS domain {ENS_DOMAIN}. Give me a moment.\n/check {ENS_DOMAIN}
15
-
16
- 3. Check if the ENS domain is available
17
- Hello! I'll help you get your domain.\n Let's start by checking your ENS domain {ENS_DOMAIN}. Give me a moment.\n/check {ENS_DOMAIN}
18
-
19
- 4. If the ENS domain is available,
20
- Looks like {ENS_DOMAIN} is available! Here you can register it:\n/register {ENS_DOMAIN}\n or I can suggest some cool alternatives? Le me know!
21
-
22
- 5. If the ENS domain is already registered, let me suggest 5 cool alternatives
23
- Looks like {ENS_DOMAIN} is already registered!\n What about these cool alternatives?\n/cool {ENS_DOMAIN}
24
-
25
- 6. If the user wants to register a ENS domain, use the command "/register [domain]"
26
- Looks like {ENS_DOMAIN} is available! Let me help you register it\n/register {ENS_DOMAIN}
27
-
28
- 7. If the user wants to directly to tip to the ENS domain owner, use directly the command "/tip [address]", this will return a url but a button to send the tip
29
- Here is the url to send the tip:\n/tip 0x...
30
-
31
- 8. If the user wants to get information about the ENS domain, use the command "/info [domain]"
32
- Hello! I'll help you get info about {ENS_DOMAIN}.\n Give me a moment.\n/info {ENS_DOMAIN}
33
-
34
- 9. If the user wants to renew their domain, use the command "/renew [domain]"
35
- Hello! I'll help you get your ENS domain.\n Let's start by checking your ENS domain {ENS_DOMAIN}. Give me a moment.\n/renew {ENS_DOMAIN}
36
-
37
- 10. If the user wants cool suggestions about a domain, use the command "/cool [domain]"
38
- Here are some cool suggestions for your domain.\n/cool {ENS_DOMAIN}
39
-
40
- ## Most common bugs
41
-
42
- 1. Some times you will say something like: "Looks like vitalik.eth is registered! What about these cool alternatives?"
43
- But you forgot to add the command at the end of the message.
44
- You should have said something like: "Looks like vitalik.eth is registered! What about these cool alternatives?\n/cool vitalik.eth
45
- `;
46
-
47
- return defaultPromptTemplate(fineTuning, senderAddress, skills, "@ens");
48
- }
49
-
50
- run(async (context: HandlerContext) => {
51
- agentRun(context, async (address: string) => {
52
- const result = (await agent_prompt(address)) ?? "No response available";
53
- return result;
54
- });
55
- });
1
+ import { run, agentReply, replaceVariables } from "@xmtp/message-kit";
2
+ import { systemPrompt } from "./prompt.js";
3
+ import { registerSkill as checkSkill } from "./handlers/check.js";
4
+ import { registerSkill as coolSkill } from "./handlers/cool.js";
5
+ import { registerSkill as infoSkill } from "./handlers/info.js";
6
+ import { registerSkill as registerSkill } from "./handlers/register.js";
7
+ import { registerSkill as renewSkill } from "./handlers/renew.js";
8
+ import { registerSkill as resetSkill } from "./handlers/reset.js";
9
+ import { registerSkill as tipSkill } from "./handlers/tip.js";
10
+ import fs from "fs";
11
+
12
+ export const frameUrl = "https://ens.steer.fun/";
13
+ export const ensUrl = "https://app.ens.domains/";
14
+ export const txpayUrl = "https://txpay.vercel.app";
15
+
16
+ export const skills = [
17
+ {
18
+ name: "Ens Domain Bot",
19
+ tag: "@ens",
20
+ description: "Register ENS domains.",
21
+ skills: [
22
+ ...checkSkill,
23
+ ...coolSkill,
24
+ ...infoSkill,
25
+ ...registerSkill,
26
+ ...renewSkill,
27
+ ...resetSkill,
28
+ ...tipSkill,
29
+ ],
30
+ },
31
+ ];
32
+
33
+ run(
34
+ async (context) => {
35
+ const {
36
+ message: { sender },
37
+ runConfig,
38
+ } = context;
39
+
40
+ let prompt = await replaceVariables(
41
+ systemPrompt,
42
+ sender.address,
43
+ runConfig?.skills,
44
+ "@ens",
45
+ );
46
+ fs.writeFileSync("example_prompt.md", prompt);
47
+ await agentReply(context, prompt);
48
+ },
49
+ { skills },
50
+ );
@@ -0,0 +1,52 @@
1
+ export const systemPrompt = `
2
+ Your are helpful and playful agent called {agent_name} that lives inside a web3 messaging app called Converse.
3
+
4
+ {rules}
5
+
6
+ {user_context}
7
+
8
+ {skills}
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
+ /tip [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. Sometimes 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.
52
+ `;
@@ -1,38 +1,18 @@
1
- import {
2
- run,
3
- HandlerContext,
4
- textGeneration,
5
- processMultilineResponse,
6
- } from "@xmtp/message-kit";
7
- import { agent_prompt } from "./prompt.js";
1
+ import { run, agentReply, replaceVariables } from "@xmtp/message-kit";
8
2
 
9
- if (!process.env.OPEN_AI_API_KEY) {
10
- console.error("OPEN_AI_API_KEY is not set");
11
- }
12
-
13
- run(async (context: HandlerContext) => {
14
- if (!process.env.OPEN_AI_API_KEY) {
15
- context.send("gm");
16
- return;
17
- }
3
+ import { systemPrompt } from "./prompt.js";
18
4
 
5
+ run(async (context) => {
19
6
  const {
20
- message: {
21
- content: { text, params },
22
- sender,
23
- },
7
+ message: { sender },
8
+ runConfig,
24
9
  } = context;
25
10
 
26
- try {
27
- let userPrompt = params?.prompt ?? text;
28
- const { reply } = await textGeneration(
29
- sender.address,
30
- userPrompt,
31
- await agent_prompt(sender.address),
32
- );
33
- await processMultilineResponse(sender.address, reply, context);
34
- } catch (error) {
35
- console.error("Error during OpenAI call:", error);
36
- await context.send("An error occurred while processing your request.");
37
- }
11
+ let prompt = await replaceVariables(
12
+ systemPrompt,
13
+ sender.address,
14
+ runConfig?.skills,
15
+ "@bot",
16
+ );
17
+ await agentReply(context, prompt);
38
18
  });
@@ -1,20 +1,10 @@
1
- import { defaultPromptTemplate } from "@xmtp/message-kit";
1
+ export const systemPrompt = `
2
+ You are a helpful and playful agent called {agent_name} that lives inside a web3 messaging app called Converse.
2
3
 
3
- export async function agent_prompt(senderAddress: string) {
4
- let fineTunedPrompt = `
5
-
6
- ### Context
7
-
8
- You are a helpful agent that lives inside a web3 messaging group that helps interpret user requests and execute commands.
9
- The message was sent by @${senderAddress}
10
-
4
+ {rules}
11
5
 
12
- Important:
13
- - If a user asks jokes, make jokes about web3 devs\n
14
- - If the user asks about performing an action and you can think of a command that would help, answer directly with the command and nothing else.
15
- - Populate the command with the correct or random values. Always return commands with real values only, using usernames with @ and excluding addresses.\n
16
- - If the user asks a question or makes a statement that does not clearly map to a command, respond with helpful information or a clarification question.\n
17
- - If the user is grateful, respond asking for a tip in a playful manner.
18
- `;
19
- return defaultPromptTemplate(fineTunedPrompt, senderAddress, [], "@bot");
20
- }
6
+ {skills}
7
+
8
+ {user_context}
9
+
10
+ `;
@@ -1,7 +1,23 @@
1
- import { HandlerContext } from "@xmtp/message-kit";
1
+ import { XMTPContext } from "@xmtp/message-kit";
2
+ import type { skillAction } from "@xmtp/message-kit";
2
3
 
3
- // Handler function to process game-related
4
- export async function handler(context: HandlerContext) {
4
+ export const registerSkill: skillAction[] = [
5
+ {
6
+ skill: "/game [game]",
7
+ handler: handleGames,
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 handleGames(context: XMTPContext) {
5
21
  const {
6
22
  message: {
7
23
  content: { skill, params, text },
@@ -1,18 +1,37 @@
1
- import { HandlerContext } from "@xmtp/message-kit";
1
+ import { XMTPContext } from "@xmtp/message-kit";
2
2
 
3
- export async function handler(context: HandlerContext) {
3
+ import type { skillAction } from "@xmtp/message-kit";
4
+
5
+ export const registerSkill: skillAction[] = [
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) {
4
23
  const {
5
- skills,
6
24
  message: {
7
25
  content: { skill },
8
26
  },
9
27
  group,
28
+ runConfig,
10
29
  } = context;
11
30
 
12
31
  if (skill == "help") {
13
32
  const intro =
14
33
  "Available experiences:\n" +
15
- skills
34
+ runConfig?.skills
16
35
  ?.flatMap((app) => app.skills)
17
36
  .map((skill) => `${skill.skill} - ${skill.description}`)
18
37
  .join("\n") +