create-message-kit 1.0.16 → 1.0.17
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/package.json +1 -1
- package/templates/agent/src/handler/ens.ts +104 -140
- package/templates/agent/src/index.ts +8 -0
- package/templates/agent/src/lib/openai.ts +41 -29
- package/templates/agent/src/lib/resolver.ts +107 -63
- package/templates/agent/src/prompt.ts +24 -36
- package/templates/agent/src/{commands.ts → skills.ts} +33 -9
- package/templates/gm/src/index.ts +6 -13
- package/templates/group/src/handler/agent.ts +17 -10
- package/templates/group/src/handler/loyalty.ts +3 -11
- package/templates/group/src/handler/splitpayment.ts +17 -10
- package/templates/group/src/handler/tipping.ts +10 -6
- package/templates/group/src/handler/transaction.ts +10 -39
- package/templates/group/src/index.ts +24 -20
- package/templates/group/src/lib/openai.ts +42 -3
- package/templates/group/src/lib/resolver.ts +126 -0
- package/templates/group/src/{commands.ts → skills.ts} +17 -16
- package/templates/agent/src/lib/types.ts +0 -33
- package/templates/gm/src/commands.ts +0 -18
- package/templates/gm/src/handler.ts +0 -6
|
@@ -1,93 +1,81 @@
|
|
|
1
|
-
import { generateCoolAlternatives } from "./lib/resolver.js";
|
|
2
1
|
export async function ens_agent_prompt(
|
|
3
2
|
address: string,
|
|
4
3
|
domain?: string,
|
|
5
4
|
name?: string,
|
|
6
5
|
converseUsername?: string,
|
|
7
|
-
tipAddress?: string,
|
|
8
6
|
txUrl?: string,
|
|
9
7
|
) {
|
|
10
|
-
const
|
|
11
|
-
const commonAlternatives = generateCoolAlternatives(userName);
|
|
12
|
-
const systemPrompt = `You are a helpful and playful agent that lives inside a web3 messaging app.
|
|
8
|
+
const systemPrompt = `You are a helpful and playful agent that lives inside a web3 messaging app called Converse.
|
|
13
9
|
- You can respond with multiple messages if needed. Each message should be separated by a newline character.
|
|
14
10
|
- You can trigger commands by only sending the command in a newline message.
|
|
15
11
|
- Never announce actions without using a command separated by a newline character.
|
|
16
12
|
- Only provide answers based on verified information.
|
|
13
|
+
- Dont answer in markdown format, just answer in plaintext.
|
|
17
14
|
- Do not make guesses or assumptions
|
|
18
15
|
- CHECK that you are not missing a command
|
|
19
16
|
|
|
20
17
|
User context:
|
|
21
18
|
- Users address is: ${address}
|
|
22
|
-
${domain != undefined ? `- User ENS domain is: ${domain}` : "
|
|
23
|
-
${name != undefined ? `-
|
|
19
|
+
${domain != undefined ? `- User ENS domain is: ${domain}` : ""}
|
|
20
|
+
${name != undefined ? `- Converse username is: ${name}` : ""}
|
|
24
21
|
|
|
25
22
|
## Task
|
|
26
23
|
- Start by fetch their domain from or Convese username
|
|
27
24
|
- Call the user by their name or domain, in case they have one
|
|
28
25
|
- Ask for a name (if they don't have one) so you can suggest domains.
|
|
29
|
-
- Use "/check [domain] [cool_alternatives]" to see if a domain is available and offer cool alternatives
|
|
30
|
-
- To check the information about the domain by using the command "/info [domain]".
|
|
31
|
-
- To register a domain use the command "/register [domain]".
|
|
32
|
-
- To trigger renewal: "/renew [domain]".
|
|
33
|
-
- To tip the domain owner: "/tip [address]".
|
|
34
26
|
|
|
35
27
|
Commands:
|
|
36
|
-
- /info [domain]:
|
|
37
|
-
- /check [domain]
|
|
38
|
-
- /register [domain]:
|
|
39
|
-
- /renew [domain]:
|
|
40
|
-
- /tip [address]:
|
|
28
|
+
- "/info [domain]": To get information about a domain use this command.
|
|
29
|
+
- "/check [domain]": To check to see if a domain is available use this command.
|
|
30
|
+
- "/register [domain]": To register a domain use this command. This will return a url pointing to the registration page.
|
|
31
|
+
- "/renew [domain]": To trigger renewal of a domain use this command. This will return a url with a button to renew the domain.
|
|
32
|
+
- "/tip [address]": To tip a domain or address use this command. This will return a url with a button to send the tip
|
|
33
|
+
- "/cool [domain]": To get cool alternatives for a .eth domain use this command.
|
|
41
34
|
|
|
42
35
|
Examples:
|
|
43
|
-
- /check ${
|
|
36
|
+
- /check ${domain}
|
|
44
37
|
- /info nick.eth
|
|
45
38
|
- /register vitalik.eth
|
|
46
39
|
- /renew fabri.base.eth
|
|
47
40
|
- /tip 0xf0EA7663233F99D0c12370671abBb6Cca980a490
|
|
41
|
+
- /cool vitalik.eth
|
|
48
42
|
|
|
49
43
|
## Example response:
|
|
50
44
|
|
|
51
45
|
1. Check if the user does not have a ENS domain
|
|
52
|
-
Hey ${name}! it looks like you don't have a ENS domain yet! \n\
|
|
46
|
+
Hey ${name}! it looks like you don't have a ENS domain yet! \n\Let me start by checking your Converse username ${converseUsername}.eth\n/check ${converseUsername}.eth
|
|
53
47
|
|
|
54
48
|
2. If the user has a ENS domain
|
|
55
|
-
Hello ${domain} ! I'll help you get your ENS domain.\n Let's start by checking your ENS domain ${domain}. Give me a moment.\n/check ${domain}
|
|
49
|
+
Hello ${domain} ! I'll help you get your ENS domain.\n Let's start by checking your ENS domain ${domain}. Give me a moment.\n/check ${domain}
|
|
56
50
|
|
|
57
51
|
3. Check if the ENS domain is available
|
|
58
|
-
Hello! I'll help you get your domain.\n Let's start by checking your ENS domain ${domain}. Give me a moment.\n/check ${domain}
|
|
52
|
+
Hello! I'll help you get your domain.\n Let's start by checking your ENS domain ${domain}. Give me a moment.\n/check ${domain}
|
|
59
53
|
|
|
60
54
|
4. If the ENS domain is available,
|
|
61
|
-
Looks like ${domain} is available! Would you like to register it?\n/register ${domain}\n or I can suggest some cool alternatives? Le me know
|
|
55
|
+
Looks like ${domain} is available! Would you like to register it?\n/register ${domain}\n or I can suggest some cool alternatives? Le me know!
|
|
62
56
|
|
|
63
57
|
5. If the ENS domain is already registered, let me suggest 5 cool alternatives
|
|
64
|
-
Looks like ${domain} is already registered!\n What about these cool alternatives
|
|
58
|
+
Looks like ${domain} is already registered!\n What about these cool alternatives?\n/cool ${domain}
|
|
65
59
|
|
|
66
60
|
6. If the user wants to register a ENS domain, use the command "/register [domain]"
|
|
67
61
|
Looks like ${domain} is available! Let me help you register it\n/register ${domain}
|
|
68
62
|
|
|
69
|
-
7. If the user wants to tip the ENS domain owner, use the command "/tip [
|
|
70
|
-
|
|
63
|
+
7. If the user wants to directly to tip to the ENS domain owner, use directly the command "/tip [domain]", this will return a url but a button to send the tip
|
|
64
|
+
Here is the url to send the tip:\n/tip ${domain}
|
|
71
65
|
|
|
72
|
-
8.
|
|
73
|
-
Here is the url to send the tip:\n${txUrl}
|
|
74
|
-
|
|
75
|
-
9. If the user wants to get information about the ENS domain, use the command "/info [domain]"
|
|
66
|
+
8. If the user wants to get information about the ENS domain, use the command "/info [domain]"
|
|
76
67
|
Hello! I'll help you get info about ${domain}.\n Give me a moment.\n/info ${domain}
|
|
77
68
|
|
|
78
|
-
|
|
69
|
+
9. If the user wants to renew their domain, use the command "/renew [domain]"
|
|
79
70
|
Hello! I'll help you get your ENS domain.\n Let's start by checking your ENS domain ${domain}. Give me a moment.\n/renew ${domain}
|
|
80
71
|
|
|
81
|
-
|
|
82
|
-
Here
|
|
83
|
-
|
|
84
|
-
12. If the user wants cool suggestions about a domain, use the command "/cool [domain]"
|
|
85
|
-
Here are some cool suggestions for ${domain}: "${commonAlternatives}"
|
|
72
|
+
10. If the user wants cool suggestions about a domain, use the command "/cool [domain]"
|
|
73
|
+
Here are some cool suggestions for your domain.\n/cool ${domain}
|
|
86
74
|
|
|
87
75
|
## Most common bug
|
|
88
76
|
Some times you will say something like: "Looks like vitalik.eth is registered! What about these cool alternatives?"
|
|
89
77
|
But you forgot to add the command at the end of the message.
|
|
90
|
-
You should have said something like: "Looks like vitalik.eth is registered! What about these cool alternatives?\n/
|
|
78
|
+
You should have said something like: "Looks like vitalik.eth is registered! What about these cool alternatives?\n/cool vitalik.eth
|
|
91
79
|
`;
|
|
92
80
|
return systemPrompt;
|
|
93
81
|
}
|
|
@@ -1,16 +1,18 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import {
|
|
1
|
+
import type { SkillGroup } from "@xmtp/message-kit";
|
|
2
|
+
import { handleEns } from "./handler/ens.js";
|
|
3
3
|
|
|
4
|
-
export const
|
|
4
|
+
export const skills: SkillGroup[] = [
|
|
5
5
|
{
|
|
6
6
|
name: "Ens Domain Bot",
|
|
7
7
|
description: "Register ENS domains.",
|
|
8
|
-
|
|
8
|
+
skills: [
|
|
9
9
|
{
|
|
10
10
|
command: "/register [domain]",
|
|
11
11
|
triggers: ["/register", "@ensbot"],
|
|
12
12
|
handler: handleEns,
|
|
13
|
-
description:
|
|
13
|
+
description:
|
|
14
|
+
"Register a new ENS domain. Returns a URL to complete the registration process.",
|
|
15
|
+
example: "/register vitalik.eth",
|
|
14
16
|
params: {
|
|
15
17
|
domain: {
|
|
16
18
|
type: "string",
|
|
@@ -21,7 +23,9 @@ export const commands: CommandGroup[] = [
|
|
|
21
23
|
command: "/info [domain]",
|
|
22
24
|
triggers: ["/info", "@ensbot"],
|
|
23
25
|
handler: handleEns,
|
|
24
|
-
description:
|
|
26
|
+
description:
|
|
27
|
+
"Get detailed information about an ENS domain including owner, expiry date, and resolver.",
|
|
28
|
+
example: "/info nick.eth",
|
|
25
29
|
params: {
|
|
26
30
|
domain: {
|
|
27
31
|
type: "string",
|
|
@@ -32,7 +36,9 @@ export const commands: CommandGroup[] = [
|
|
|
32
36
|
command: "/renew [domain]",
|
|
33
37
|
triggers: ["/renew", "@ensbot"],
|
|
34
38
|
handler: handleEns,
|
|
35
|
-
description:
|
|
39
|
+
description:
|
|
40
|
+
"Extend the registration period of your ENS domain. Returns a URL to complete the renewal.",
|
|
41
|
+
example: "/renew fabri.base.eth",
|
|
36
42
|
params: {
|
|
37
43
|
domain: {
|
|
38
44
|
type: "string",
|
|
@@ -53,14 +59,32 @@ export const commands: CommandGroup[] = [
|
|
|
53
59
|
},
|
|
54
60
|
},
|
|
55
61
|
},
|
|
62
|
+
{
|
|
63
|
+
command: "/cool [domain]",
|
|
64
|
+
triggers: ["/cool"],
|
|
65
|
+
handler: handleEns,
|
|
66
|
+
description: "Get cool alternatives for a .eth domain.",
|
|
67
|
+
params: {
|
|
68
|
+
domain: {
|
|
69
|
+
type: "string",
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
command: "/reset",
|
|
75
|
+
triggers: ["/reset"],
|
|
76
|
+
handler: handleEns,
|
|
77
|
+
description: "Reset the conversation.",
|
|
78
|
+
params: {},
|
|
79
|
+
},
|
|
56
80
|
{
|
|
57
81
|
command: "/tip [address]",
|
|
58
82
|
description: "Show a URL for tipping a domain owner.",
|
|
59
83
|
triggers: ["/tip"],
|
|
60
|
-
handler:
|
|
84
|
+
handler: handleEns,
|
|
61
85
|
params: {
|
|
62
86
|
address: {
|
|
63
|
-
type: "
|
|
87
|
+
type: "string",
|
|
64
88
|
},
|
|
65
89
|
},
|
|
66
90
|
},
|
|
@@ -1,16 +1,9 @@
|
|
|
1
1
|
import { run, HandlerContext } from "@xmtp/message-kit";
|
|
2
2
|
|
|
3
|
-
run(
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
const { content, sender } = context.message;
|
|
3
|
+
run(async (context: HandlerContext) => {
|
|
4
|
+
// Get the message and the address from the sender
|
|
5
|
+
const { content, sender } = context.message;
|
|
7
6
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
{
|
|
12
|
-
memberChange: true,
|
|
13
|
-
attachments: true,
|
|
14
|
-
experimental: true,
|
|
15
|
-
},
|
|
16
|
-
);
|
|
7
|
+
// To reply, just call `reply` on the HandlerContext
|
|
8
|
+
await context.send(`gm`);
|
|
9
|
+
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { HandlerContext,
|
|
1
|
+
import { HandlerContext, AbstractedMember } from "@xmtp/message-kit";
|
|
2
2
|
import { textGeneration } from "../lib/openai.js";
|
|
3
3
|
|
|
4
4
|
export async function handler(context: HandlerContext) {
|
|
@@ -9,19 +9,21 @@ export async function handler(context: HandlerContext) {
|
|
|
9
9
|
|
|
10
10
|
const {
|
|
11
11
|
message: {
|
|
12
|
+
sender,
|
|
12
13
|
content: { content, params },
|
|
13
14
|
},
|
|
14
15
|
} = context;
|
|
15
16
|
|
|
16
17
|
const systemPrompt = generateSystemPrompt(context);
|
|
17
|
-
console.log("systemPrompt", systemPrompt);
|
|
18
18
|
try {
|
|
19
19
|
let userPrompt = params?.prompt ?? content;
|
|
20
|
-
console.log("userPrompt", userPrompt);
|
|
21
20
|
|
|
22
|
-
const { reply } = await textGeneration(
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
const { reply } = await textGeneration(
|
|
22
|
+
sender.address,
|
|
23
|
+
userPrompt,
|
|
24
|
+
systemPrompt,
|
|
25
|
+
);
|
|
26
|
+
context.skill(reply);
|
|
25
27
|
} catch (error) {
|
|
26
28
|
console.error("Error during OpenAI call:", error);
|
|
27
29
|
await context.reply("An error occurred while processing your request.");
|
|
@@ -31,7 +33,7 @@ export async function handler(context: HandlerContext) {
|
|
|
31
33
|
function generateSystemPrompt(context: HandlerContext) {
|
|
32
34
|
const {
|
|
33
35
|
members,
|
|
34
|
-
|
|
36
|
+
skills,
|
|
35
37
|
message: { sender },
|
|
36
38
|
} = context;
|
|
37
39
|
|
|
@@ -40,10 +42,15 @@ function generateSystemPrompt(context: HandlerContext) {
|
|
|
40
42
|
|
|
41
43
|
You are a helpful bot agent that lives inside a web3 messaging group that helps interpret user requests and execute commands.
|
|
42
44
|
#### Users
|
|
43
|
-
${JSON.stringify(
|
|
45
|
+
${JSON.stringify(
|
|
46
|
+
members?.map((member: AbstractedMember) => ({
|
|
47
|
+
...member,
|
|
48
|
+
username: `@${member.accountAddresses[0]}`,
|
|
49
|
+
})),
|
|
50
|
+
)}\n
|
|
44
51
|
#### Commands
|
|
45
|
-
${JSON.stringify(
|
|
46
|
-
The message was sent by @${sender?.
|
|
52
|
+
${JSON.stringify(skills)}\n
|
|
53
|
+
The message was sent by @${sender?.address}
|
|
47
54
|
|
|
48
55
|
### Examples
|
|
49
56
|
prompt /agent tip alix and bo
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { HandlerContext,
|
|
1
|
+
import { HandlerContext, AbstractedMember } from "@xmtp/message-kit";
|
|
2
2
|
import { getStackClient } from "../lib/stack.js";
|
|
3
3
|
|
|
4
4
|
export async function handler(context: HandlerContext, fake?: boolean) {
|
|
@@ -6,15 +6,8 @@ export async function handler(context: HandlerContext, fake?: boolean) {
|
|
|
6
6
|
const {
|
|
7
7
|
members,
|
|
8
8
|
group,
|
|
9
|
-
|
|
10
|
-
message: {
|
|
11
|
-
content,
|
|
12
|
-
content: { command },
|
|
13
|
-
sender,
|
|
14
|
-
typeId,
|
|
15
|
-
},
|
|
9
|
+
message: { sender, typeId, content },
|
|
16
10
|
} = context;
|
|
17
|
-
console.log(command);
|
|
18
11
|
if (typeId === "text" && group) {
|
|
19
12
|
const { command } = content;
|
|
20
13
|
if (command === "points") {
|
|
@@ -40,14 +33,13 @@ export async function handler(context: HandlerContext, fake?: boolean) {
|
|
|
40
33
|
} else if (typeId === "group_updated" && group) {
|
|
41
34
|
const { initiatedByInboxId, addedInboxes } = content;
|
|
42
35
|
const adminAddress = members?.find(
|
|
43
|
-
(member:
|
|
36
|
+
(member: AbstractedMember) => member.inboxId === initiatedByInboxId,
|
|
44
37
|
);
|
|
45
38
|
if (addedInboxes && addedInboxes.length > 0) {
|
|
46
39
|
//if add someone to the group
|
|
47
40
|
await stack?.track("referral", {
|
|
48
41
|
points: 10,
|
|
49
42
|
account: adminAddress?.address ?? "",
|
|
50
|
-
uniqueId: adminAddress?.username ?? "",
|
|
51
43
|
});
|
|
52
44
|
}
|
|
53
45
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { HandlerContext } from "@xmtp/message-kit";
|
|
2
2
|
import { vision, textGeneration } from "../lib/openai.js";
|
|
3
|
+
import { getUserInfo } from "../lib/resolver.js";
|
|
3
4
|
|
|
4
5
|
export async function handler(context: HandlerContext) {
|
|
5
6
|
if (!process?.env?.OPEN_AI_API_KEY) {
|
|
@@ -8,7 +9,7 @@ export async function handler(context: HandlerContext) {
|
|
|
8
9
|
}
|
|
9
10
|
const {
|
|
10
11
|
members,
|
|
11
|
-
|
|
12
|
+
skills,
|
|
12
13
|
message: {
|
|
13
14
|
typeId,
|
|
14
15
|
content: { attachment },
|
|
@@ -16,8 +17,12 @@ export async function handler(context: HandlerContext) {
|
|
|
16
17
|
},
|
|
17
18
|
} = context;
|
|
18
19
|
|
|
20
|
+
if (!members) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
let senderInfo = await getUserInfo(sender.address);
|
|
19
24
|
if (attachment && typeId === "remoteStaticAttachment") {
|
|
20
|
-
const { data
|
|
25
|
+
const { data } = attachment;
|
|
21
26
|
const response = await vision(
|
|
22
27
|
data,
|
|
23
28
|
"This image is the bill of a restaurant dinner. Return the total. If you can't find the total, return 'undefined'.",
|
|
@@ -31,9 +36,6 @@ export async function handler(context: HandlerContext) {
|
|
|
31
36
|
}
|
|
32
37
|
if (response) {
|
|
33
38
|
const prompt = `You a split wise agent that splits the bill between the members of this group except for the sender and bot.\n
|
|
34
|
-
These are the users of the group: ${JSON.stringify(members?.map((member) => ({ ...member, username: `@${member.username}` })))}\n
|
|
35
|
-
This group app has many commands available: ${JSON.stringify(commands)}\n
|
|
36
|
-
|
|
37
39
|
|
|
38
40
|
## Instructions:
|
|
39
41
|
When you receive the totals you should split the bill between the members of the group and send to each one a transaction frame
|
|
@@ -44,18 +46,23 @@ export async function handler(context: HandlerContext) {
|
|
|
44
46
|
Example:
|
|
45
47
|
[
|
|
46
48
|
"This are the details: Total: $49.52. Tip (20%): $9.90",
|
|
47
|
-
"All users owe X USDC to @${
|
|
48
|
-
"/send @${
|
|
49
|
+
"All users owe X USDC to @${senderInfo?.converseUsername}. Pay here:",
|
|
50
|
+
"/send @${senderInfo?.converseUsername} $9.90"
|
|
49
51
|
]
|
|
50
52
|
`;
|
|
51
53
|
|
|
52
54
|
//I want the reply to be an array of messages so the bot feels like is sending multuple ones
|
|
53
|
-
const { reply } = await textGeneration(
|
|
55
|
+
const { reply } = await textGeneration(
|
|
56
|
+
sender.address,
|
|
57
|
+
response,
|
|
58
|
+
prompt,
|
|
59
|
+
true,
|
|
60
|
+
);
|
|
54
61
|
let splitMessages = JSON.parse(reply);
|
|
55
62
|
for (const message of splitMessages) {
|
|
56
63
|
let msg = message as string;
|
|
57
|
-
if (msg.startsWith("/")) await context.
|
|
58
|
-
else await context.
|
|
64
|
+
if (msg.startsWith("/")) await context.skill(msg);
|
|
65
|
+
else await context.send(msg);
|
|
59
66
|
}
|
|
60
67
|
}
|
|
61
68
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { HandlerContext,
|
|
1
|
+
import { HandlerContext, AbstractedMember } from "@xmtp/message-kit";
|
|
2
|
+
import { getUserInfo } from "../lib/resolver.js";
|
|
2
3
|
|
|
3
4
|
export async function handler(context: HandlerContext) {
|
|
4
5
|
const {
|
|
@@ -6,16 +7,15 @@ export async function handler(context: HandlerContext) {
|
|
|
6
7
|
getMessageById,
|
|
7
8
|
message: { content, sender, typeId },
|
|
8
9
|
} = context;
|
|
10
|
+
console.log(sender);
|
|
9
11
|
const msg = await getMessageById(content.reference);
|
|
10
12
|
const replyReceiver = members?.find(
|
|
11
13
|
(member) => member.inboxId === msg?.senderInboxId,
|
|
12
14
|
);
|
|
13
15
|
let amount: number = 0,
|
|
14
|
-
receivers:
|
|
16
|
+
receivers: AbstractedMember[] = [];
|
|
15
17
|
// Handle different types of messages
|
|
16
18
|
if (typeId === "reply" && replyReceiver) {
|
|
17
|
-
// Process reply messages/
|
|
18
|
-
//ha
|
|
19
19
|
const { content: reply } = content;
|
|
20
20
|
|
|
21
21
|
if (reply.includes("degen")) {
|
|
@@ -31,18 +31,22 @@ export async function handler(context: HandlerContext) {
|
|
|
31
31
|
// Process text commands starting with "/tip"
|
|
32
32
|
const {
|
|
33
33
|
params: { amount: extractedAmount, username },
|
|
34
|
-
content: text,
|
|
35
34
|
} = content;
|
|
36
35
|
amount = extractedAmount || 10; // Default amount if not specified
|
|
37
|
-
|
|
36
|
+
|
|
37
|
+
receivers = await Promise.all(
|
|
38
|
+
username.map((username: string) => getUserInfo(username)),
|
|
39
|
+
);
|
|
38
40
|
}
|
|
39
41
|
}
|
|
40
42
|
if (!sender || receivers.length === 0 || amount === 0) {
|
|
41
43
|
context.reply("Sender or receiver or amount not found.");
|
|
42
44
|
return;
|
|
43
45
|
}
|
|
46
|
+
console.log(receivers);
|
|
44
47
|
const receiverAddresses = receivers.map((receiver) => receiver.address);
|
|
45
48
|
// Process sending tokens to each receiver
|
|
49
|
+
|
|
46
50
|
context.sendTo(
|
|
47
51
|
`You received ${amount} tokens from ${sender.address}.`,
|
|
48
52
|
receiverAddresses,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { HandlerContext } from "@xmtp/message-kit";
|
|
2
|
+
import { getUserInfo } from "../lib/resolver.js";
|
|
2
3
|
|
|
3
4
|
// Main handler function for processing commands
|
|
4
5
|
export async function handler(context: HandlerContext) {
|
|
@@ -13,20 +14,17 @@ export async function handler(context: HandlerContext) {
|
|
|
13
14
|
case "send":
|
|
14
15
|
// Destructure and validate parameters for the send command
|
|
15
16
|
const { amount: amountSend, token: tokenSend, username } = params; // [!code hl] // [!code focus]
|
|
16
|
-
|
|
17
|
-
if (!amountSend || !tokenSend || !
|
|
17
|
+
let senderInfo = await getUserInfo(username);
|
|
18
|
+
if (!amountSend || !tokenSend || !senderInfo) {
|
|
18
19
|
context.reply(
|
|
19
20
|
"Missing required parameters. Please provide amount, token, and username.",
|
|
20
21
|
);
|
|
21
22
|
return;
|
|
22
23
|
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
receiver: username[0]?.address,
|
|
28
|
-
});
|
|
29
|
-
context.reply(`${url_send}`);
|
|
24
|
+
let name = senderInfo.converseUsername || senderInfo.address;
|
|
25
|
+
|
|
26
|
+
let sendUrl = `${baseUrl}/?transaction_type=send&amount=${amountSend}&token=${tokenSend}&receiver=${senderInfo.address}`;
|
|
27
|
+
context.send(`${sendUrl}`);
|
|
30
28
|
break;
|
|
31
29
|
case "swap":
|
|
32
30
|
// Destructure and validate parameters for the swap command
|
|
@@ -38,13 +36,9 @@ export async function handler(context: HandlerContext) {
|
|
|
38
36
|
);
|
|
39
37
|
return;
|
|
40
38
|
}
|
|
41
|
-
|
|
42
|
-
let
|
|
43
|
-
|
|
44
|
-
token_from,
|
|
45
|
-
token_to,
|
|
46
|
-
});
|
|
47
|
-
context.reply(`${url_swap}`);
|
|
39
|
+
|
|
40
|
+
let swapUrl = `${baseUrl}/?transaction_type=swap&token_from=${token_from}&token_to=${token_to}&amount=${amount}`;
|
|
41
|
+
context.send(`${swapUrl}`);
|
|
48
42
|
break;
|
|
49
43
|
case "show": // [!code hl] // [!code focus]
|
|
50
44
|
// Show the base URL without the transaction path
|
|
@@ -55,26 +49,3 @@ export async function handler(context: HandlerContext) {
|
|
|
55
49
|
context.reply("Unknown command. Use help to see all available commands.");
|
|
56
50
|
}
|
|
57
51
|
}
|
|
58
|
-
|
|
59
|
-
// Function to generate a URL with query parameters for transactions
|
|
60
|
-
function generateFrameURL(
|
|
61
|
-
baseUrl: string,
|
|
62
|
-
transaction_type: string,
|
|
63
|
-
params: { [key: string]: string | number | string[] | undefined },
|
|
64
|
-
) {
|
|
65
|
-
// Filter out undefined parameters
|
|
66
|
-
let filteredParams: {
|
|
67
|
-
[key: string]: string | number | string[] | undefined;
|
|
68
|
-
} = {};
|
|
69
|
-
|
|
70
|
-
for (const key in params) {
|
|
71
|
-
if (params[key] !== undefined) {
|
|
72
|
-
filteredParams[key] = params[key];
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
let queryParams = new URLSearchParams({
|
|
76
|
-
transaction_type,
|
|
77
|
-
...filteredParams,
|
|
78
|
-
}).toString();
|
|
79
|
-
return `${baseUrl}?${queryParams}`;
|
|
80
|
-
}
|
|
@@ -1,22 +1,26 @@
|
|
|
1
1
|
import { run, HandlerContext } from "@xmtp/message-kit";
|
|
2
|
-
import { handler as tipping } from "./handler/tipping.js";
|
|
3
|
-
import { handler as agent } from "./handler/agent.js";
|
|
4
2
|
import { handler as splitpayment } from "./handler/splitpayment.js";
|
|
5
3
|
|
|
6
4
|
// Main function to run the app
|
|
7
|
-
run(
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
5
|
+
run(
|
|
6
|
+
async (context: HandlerContext) => {
|
|
7
|
+
const {
|
|
8
|
+
message: { typeId },
|
|
9
|
+
} = context;
|
|
10
|
+
switch (typeId) {
|
|
11
|
+
case "reply":
|
|
12
|
+
handleReply(context);
|
|
13
|
+
break;
|
|
14
|
+
case "remoteStaticAttachment":
|
|
15
|
+
handleAttachment(context);
|
|
16
|
+
break;
|
|
17
|
+
}
|
|
18
|
+
if (!context.group) {
|
|
19
|
+
context.send("This is a group bot, add this address to a group");
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
{ attachments: true },
|
|
23
|
+
);
|
|
20
24
|
async function handleReply(context: HandlerContext) {
|
|
21
25
|
const {
|
|
22
26
|
v2client,
|
|
@@ -32,7 +36,7 @@ async function handleReply(context: HandlerContext) {
|
|
|
32
36
|
version,
|
|
33
37
|
v2client.address,
|
|
34
38
|
);
|
|
35
|
-
//await context.
|
|
39
|
+
//await context.skill(chain);
|
|
36
40
|
}
|
|
37
41
|
|
|
38
42
|
// Handle attachment messages
|
|
@@ -41,12 +45,12 @@ async function handleAttachment(context: HandlerContext) {
|
|
|
41
45
|
}
|
|
42
46
|
|
|
43
47
|
export async function helpHandler(context: HandlerContext) {
|
|
44
|
-
const {
|
|
48
|
+
const { skills } = context;
|
|
45
49
|
const intro =
|
|
46
50
|
"Available experiences:\n" +
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
.map((
|
|
51
|
+
skills
|
|
52
|
+
?.flatMap((app) => app.skills)
|
|
53
|
+
.map((skill) => `${skill.command} - ${skill.description}`)
|
|
50
54
|
.join("\n") +
|
|
51
55
|
"\nUse these commands to interact with specific apps.";
|
|
52
56
|
context.send(intro);
|
|
@@ -6,12 +6,17 @@ const openai = new OpenAI({
|
|
|
6
6
|
apiKey: process.env.OPEN_AI_API_KEY,
|
|
7
7
|
});
|
|
8
8
|
|
|
9
|
+
export type ChatHistoryEntry = { role: string; content: string };
|
|
10
|
+
export type ChatHistories = Record<string, ChatHistoryEntry[]>;
|
|
11
|
+
|
|
12
|
+
let chatHistories: ChatHistories = {};
|
|
9
13
|
export async function textGeneration(
|
|
14
|
+
address: string,
|
|
10
15
|
userPrompt: string,
|
|
11
16
|
systemPrompt: string,
|
|
12
|
-
|
|
17
|
+
isGroup: boolean = false,
|
|
13
18
|
) {
|
|
14
|
-
let messages =
|
|
19
|
+
let messages = chatHistories[address] || [];
|
|
15
20
|
if (messages.length === 0) {
|
|
16
21
|
messages.push({
|
|
17
22
|
role: "system",
|
|
@@ -33,7 +38,7 @@ export async function textGeneration(
|
|
|
33
38
|
content: reply || "No response from OpenAI.",
|
|
34
39
|
});
|
|
35
40
|
const cleanedReply = responseParser(reply as string);
|
|
36
|
-
|
|
41
|
+
if (!isGroup) chatHistories[address] = messages;
|
|
37
42
|
return { reply: cleanedReply, history: messages };
|
|
38
43
|
} catch (error) {
|
|
39
44
|
console.error("Failed to fetch from OpenAI:", error);
|
|
@@ -78,6 +83,35 @@ export async function vision(imageData: Uint8Array, systemPrompt: string) {
|
|
|
78
83
|
}
|
|
79
84
|
}
|
|
80
85
|
|
|
86
|
+
export async function processResponseWithskill(
|
|
87
|
+
address: string,
|
|
88
|
+
reply: string,
|
|
89
|
+
context: any,
|
|
90
|
+
) {
|
|
91
|
+
let messages = reply
|
|
92
|
+
.split("\n")
|
|
93
|
+
.map((message: string) => responseParser(message))
|
|
94
|
+
.filter((message): message is string => message.length > 0);
|
|
95
|
+
|
|
96
|
+
console.log(messages);
|
|
97
|
+
for (const message of messages) {
|
|
98
|
+
if (message.startsWith("/")) {
|
|
99
|
+
const response = await context.skill(message);
|
|
100
|
+
if (response && response.message) {
|
|
101
|
+
let msg = responseParser(response.message);
|
|
102
|
+
|
|
103
|
+
chatHistories[address].push({
|
|
104
|
+
role: "system",
|
|
105
|
+
content: msg,
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
await context.send(response.message);
|
|
109
|
+
}
|
|
110
|
+
} else {
|
|
111
|
+
await context.send(message);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
81
115
|
export function responseParser(message: string) {
|
|
82
116
|
let trimmedMessage = message;
|
|
83
117
|
// Remove bold and underline markdown
|
|
@@ -94,5 +128,10 @@ export function responseParser(message: string) {
|
|
|
94
128
|
trimmedMessage = trimmedMessage?.replace(/^\s+|\s+$/g, "");
|
|
95
129
|
// Remove any remaining leading or trailing whitespace
|
|
96
130
|
trimmedMessage = trimmedMessage.trim();
|
|
131
|
+
|
|
97
132
|
return trimmedMessage;
|
|
98
133
|
}
|
|
134
|
+
|
|
135
|
+
export const clearChatHistories = () => {
|
|
136
|
+
chatHistories = {};
|
|
137
|
+
};
|