create-message-kit 1.1.7-beta.8 → 1.1.8
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/README.md +2 -2
- package/index.js +60 -50
- package/package.json +1 -1
- package/templates/agent/src/handler/ens.ts +14 -12
- package/templates/agent/src/index.ts +2 -10
- package/templates/agent/src/prompt.ts +28 -22
- package/templates/agent/src/skills.ts +8 -9
- package/templates/gm/.env.example +1 -1
- package/templates/gm/src/index.ts +1 -5
- package/templates/group/.env.example +2 -3
- package/templates/group/src/handler/game.ts +4 -5
- package/templates/group/src/handler/helpers.ts +10 -6
- package/templates/group/src/handler/payment.ts +29 -0
- package/templates/group/src/handler/tipping.ts +17 -35
- package/templates/group/src/index.ts +23 -26
- package/templates/group/src/prompt.ts +45 -0
- package/templates/group/src/skills.ts +17 -107
- package/templates/agent/package.json +0 -22
- package/templates/agent/src/lib/gpt.ts +0 -161
- package/templates/agent/src/lib/openai.ts +0 -174
- package/templates/agent/src/lib/resolver.ts +0 -151
- package/templates/gm/package.json +0 -21
- package/templates/group/package.json +0 -23
- package/templates/group/src/handler/agent.ts +0 -67
- package/templates/group/src/handler/group.ts +0 -24
- package/templates/group/src/handler/loyalty.ts +0 -46
- package/templates/group/src/handler/splitpayment.ts +0 -65
- package/templates/group/src/handler/transaction.ts +0 -50
- package/templates/group/src/lib/gpt.ts +0 -161
- package/templates/group/src/lib/openai.ts +0 -174
- package/templates/group/src/lib/resolver.ts +0 -151
- package/templates/group/src/lib/stack.ts +0 -18
- package/templates/group/src/lib/vision.ts +0 -42
@@ -1,34 +1,31 @@
|
|
1
1
|
import { run, HandlerContext } from "@xmtp/message-kit";
|
2
|
+
import { textGeneration, processMultilineResponse } from "@xmtp/message-kit";
|
3
|
+
import { agent_prompt } from "./prompt.js";
|
4
|
+
import { getUserInfo } from "@xmtp/message-kit";
|
2
5
|
|
3
|
-
// Main function to run the app
|
4
6
|
run(async (context: HandlerContext) => {
|
5
7
|
const {
|
6
|
-
message: { typeId },
|
7
|
-
group,
|
8
|
-
} = context;
|
9
|
-
switch (typeId) {
|
10
|
-
case "reply":
|
11
|
-
handleReply(context);
|
12
|
-
break;
|
13
|
-
}
|
14
|
-
if (!group) {
|
15
|
-
context.send("This is a group bot, add this address to a group");
|
16
|
-
}
|
17
|
-
});
|
18
|
-
async function handleReply(context: HandlerContext) {
|
19
|
-
const {
|
20
|
-
v2client,
|
21
|
-
getReplyChain,
|
22
|
-
version,
|
23
8
|
message: {
|
24
|
-
content: {
|
9
|
+
content: { text, params },
|
10
|
+
sender,
|
25
11
|
},
|
26
12
|
} = context;
|
27
13
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
}
|
14
|
+
try {
|
15
|
+
let userPrompt = params?.prompt ?? text;
|
16
|
+
const userInfo = await getUserInfo(sender.address);
|
17
|
+
if (!userInfo) {
|
18
|
+
console.log("User info not found");
|
19
|
+
return;
|
20
|
+
}
|
21
|
+
const { reply } = await textGeneration(
|
22
|
+
sender.address,
|
23
|
+
userPrompt,
|
24
|
+
await agent_prompt(userInfo),
|
25
|
+
);
|
26
|
+
await processMultilineResponse(sender.address, reply, context);
|
27
|
+
} catch (error) {
|
28
|
+
console.error("Error during OpenAI call:", error);
|
29
|
+
await context.send("An error occurred while processing your request.");
|
30
|
+
}
|
31
|
+
});
|
@@ -0,0 +1,45 @@
|
|
1
|
+
import { skills } from "./skills.js";
|
2
|
+
import {
|
3
|
+
UserInfo,
|
4
|
+
PROMPT_USER_CONTENT,
|
5
|
+
PROMPT_RULES,
|
6
|
+
PROMPT_SKILLS_AND_EXAMPLES,
|
7
|
+
PROMPT_REPLACE_VARIABLES,
|
8
|
+
} from "@xmtp/message-kit";
|
9
|
+
|
10
|
+
export async function agent_prompt(userInfo: UserInfo) {
|
11
|
+
let systemPrompt =
|
12
|
+
PROMPT_RULES +
|
13
|
+
PROMPT_USER_CONTENT(userInfo) +
|
14
|
+
PROMPT_SKILLS_AND_EXAMPLES(skills, "@bot");
|
15
|
+
|
16
|
+
let fineTunedPrompt = `
|
17
|
+
## Example response
|
18
|
+
|
19
|
+
1. If user wants to play a game, use the skill 'game' and specify the game type.
|
20
|
+
Hey! Sure let's do that.\n/game wordle
|
21
|
+
|
22
|
+
2. When user wants to pay a specific token:
|
23
|
+
I'll help you pay 1 USDC to 0x123...\n/pay 1 {TOKE}} 0x123456789...
|
24
|
+
*This will return a url to pay
|
25
|
+
|
26
|
+
3. If the user wants to pay a eth domain:
|
27
|
+
I'll help you pay 1 USDC to vitalik.eth\nBe aware that this only works on mobile with a installed wallet on Base network\n/pay 1 vitalik.eth
|
28
|
+
*This will return a url to pay
|
29
|
+
|
30
|
+
4. If the user wants to pay a username:
|
31
|
+
I'll help you pay 1 USDC to @fabri\nBe aware that this only works on mobile with a installed wallet on Base network\n/pay 1 @fabri
|
32
|
+
*This will return a url to pay
|
33
|
+
`;
|
34
|
+
|
35
|
+
systemPrompt += fineTunedPrompt;
|
36
|
+
// Replace the variables in the system prompt
|
37
|
+
systemPrompt = PROMPT_REPLACE_VARIABLES(
|
38
|
+
systemPrompt,
|
39
|
+
userInfo?.address ?? "",
|
40
|
+
userInfo,
|
41
|
+
"@bot",
|
42
|
+
);
|
43
|
+
console.log(systemPrompt);
|
44
|
+
return systemPrompt;
|
45
|
+
}
|
@@ -1,18 +1,17 @@
|
|
1
1
|
import { handler as tipping } from "./handler/tipping.js";
|
2
|
-
import { handler as
|
3
|
-
import { handler as transaction } from "./handler/transaction.js";
|
2
|
+
import { handler as payment } from "./handler/payment.js";
|
4
3
|
import { handler as games } from "./handler/game.js";
|
5
|
-
import { handler as
|
6
|
-
import { handler as groupHelp } from "./handler/helpers.js";
|
4
|
+
import { handler as help } from "./handler/helpers.js";
|
7
5
|
import type { SkillGroup } from "@xmtp/message-kit";
|
8
6
|
|
9
7
|
export const skills: SkillGroup[] = [
|
10
8
|
{
|
11
|
-
name: "
|
12
|
-
|
9
|
+
name: "Group bot",
|
10
|
+
tag: "@bot",
|
11
|
+
description: "Group agent for tipping and transactions.",
|
13
12
|
skills: [
|
14
13
|
{
|
15
|
-
|
14
|
+
skill: "/tip [usernames] [amount] [token]",
|
16
15
|
triggers: ["/tip"],
|
17
16
|
examples: ["/tip @vitalik 10 usdc"],
|
18
17
|
description: "Tip users in a specified token.",
|
@@ -29,20 +28,13 @@ export const skills: SkillGroup[] = [
|
|
29
28
|
},
|
30
29
|
},
|
31
30
|
},
|
32
|
-
],
|
33
|
-
},
|
34
|
-
|
35
|
-
{
|
36
|
-
name: "Transactions",
|
37
|
-
description: "Multipurpose transaction frame built onbase.",
|
38
|
-
skills: [
|
39
31
|
{
|
40
|
-
|
41
|
-
triggers: ["/
|
42
|
-
examples: ["/
|
32
|
+
skill: "/pay [amount] [token] [username]",
|
33
|
+
triggers: ["/pay"],
|
34
|
+
examples: ["/pay 10 vitalik.eth"],
|
43
35
|
description:
|
44
36
|
"Send a specified amount of a cryptocurrency to a destination address.",
|
45
|
-
handler:
|
37
|
+
handler: payment,
|
46
38
|
params: {
|
47
39
|
amount: {
|
48
40
|
default: 10,
|
@@ -60,47 +52,11 @@ export const skills: SkillGroup[] = [
|
|
60
52
|
},
|
61
53
|
},
|
62
54
|
{
|
63
|
-
|
64
|
-
triggers: ["/swap"],
|
65
|
-
examples: ["/swap 10 usdc eth"],
|
66
|
-
description: "Exchange one type of cryptocurrency for another.",
|
67
|
-
handler: transaction,
|
68
|
-
params: {
|
69
|
-
amount: {
|
70
|
-
default: 10,
|
71
|
-
type: "number",
|
72
|
-
},
|
73
|
-
token_from: {
|
74
|
-
default: "usdc",
|
75
|
-
type: "string",
|
76
|
-
values: ["eth", "dai", "usdc", "degen"], // Accepted tokens
|
77
|
-
},
|
78
|
-
token_to: {
|
79
|
-
default: "eth",
|
80
|
-
type: "string",
|
81
|
-
values: ["eth", "dai", "usdc", "degen"], // Accepted tokenss
|
82
|
-
},
|
83
|
-
},
|
84
|
-
},
|
85
|
-
{
|
86
|
-
command: "/show",
|
87
|
-
triggers: ["/show"],
|
88
|
-
examples: ["/show"],
|
89
|
-
handler: transaction,
|
90
|
-
description: "Show the whole frame.",
|
91
|
-
params: {},
|
92
|
-
},
|
93
|
-
],
|
94
|
-
},
|
95
|
-
{
|
96
|
-
name: "Games",
|
97
|
-
description: "Provides various gaming experiences.",
|
98
|
-
skills: [
|
99
|
-
{
|
100
|
-
command: "/game [game]",
|
55
|
+
skill: "/game [game]",
|
101
56
|
triggers: ["/game", "🔎", "🔍"],
|
102
57
|
handler: games,
|
103
58
|
description: "Play a game.",
|
59
|
+
examples: ["/game wordle", "/game slot", "/game help"],
|
104
60
|
params: {
|
105
61
|
game: {
|
106
62
|
default: "",
|
@@ -109,65 +65,19 @@ export const skills: SkillGroup[] = [
|
|
109
65
|
},
|
110
66
|
},
|
111
67
|
},
|
112
|
-
],
|
113
|
-
},
|
114
|
-
{
|
115
|
-
name: "Loyalty",
|
116
|
-
description: "Manage group members and metadata.",
|
117
|
-
skills: [
|
118
|
-
{
|
119
|
-
command: "/points",
|
120
|
-
triggers: ["/points"],
|
121
|
-
examples: ["/points"],
|
122
|
-
handler: loyalty,
|
123
|
-
description: "Check your points.",
|
124
|
-
params: {},
|
125
|
-
},
|
126
|
-
{
|
127
|
-
command: "/leaderboard",
|
128
|
-
triggers: ["/leaderboard"],
|
129
|
-
adminOnly: true,
|
130
|
-
handler: loyalty,
|
131
|
-
description: "Check the points of a user.",
|
132
|
-
params: {},
|
133
|
-
},
|
134
|
-
],
|
135
|
-
},
|
136
|
-
{
|
137
|
-
name: "Agent",
|
138
|
-
description: "Manage agent commands.",
|
139
|
-
skills: [
|
140
|
-
{
|
141
|
-
command: "/agent [prompt]",
|
142
|
-
triggers: ["/agent", "@agent", "@bot"],
|
143
|
-
examples: ["/agent @vitalik"],
|
144
|
-
handler: agent,
|
145
|
-
description: "Manage agent commands.",
|
146
|
-
params: {
|
147
|
-
prompt: {
|
148
|
-
default: "",
|
149
|
-
type: "prompt",
|
150
|
-
},
|
151
|
-
},
|
152
|
-
},
|
153
|
-
],
|
154
|
-
},
|
155
|
-
{
|
156
|
-
name: "Help",
|
157
|
-
description: "Get help with the bot.",
|
158
|
-
skills: [
|
159
68
|
{
|
160
|
-
|
69
|
+
skill: "/help",
|
161
70
|
triggers: ["/help"],
|
162
71
|
examples: ["/help"],
|
163
|
-
handler:
|
72
|
+
handler: help,
|
164
73
|
description: "Get help with the bot.",
|
165
74
|
params: {},
|
166
75
|
},
|
167
76
|
{
|
168
|
-
|
77
|
+
skill: "/id",
|
169
78
|
adminOnly: true,
|
170
|
-
|
79
|
+
examples: ["/id"],
|
80
|
+
handler: help,
|
171
81
|
triggers: ["/id"],
|
172
82
|
description: "Get the group ID.",
|
173
83
|
params: {},
|
@@ -1,22 +0,0 @@
|
|
1
|
-
{
|
2
|
-
"name": "agent",
|
3
|
-
"private": true,
|
4
|
-
"type": "module",
|
5
|
-
"scripts": {
|
6
|
-
"build": "tsc",
|
7
|
-
"dev": "tsc -w & sleep 1 && nodemon --quiet dist/index.js",
|
8
|
-
"start": "node dist/index.js"
|
9
|
-
},
|
10
|
-
"dependencies": {
|
11
|
-
"@xmtp/message-kit": "workspace:*",
|
12
|
-
"openai": "^4.65.0"
|
13
|
-
},
|
14
|
-
"devDependencies": {
|
15
|
-
"@types/node": "^20.14.2",
|
16
|
-
"nodemon": "^3.1.3",
|
17
|
-
"typescript": "^5.4.5"
|
18
|
-
},
|
19
|
-
"engines": {
|
20
|
-
"node": ">=20"
|
21
|
-
}
|
22
|
-
}
|
@@ -1,161 +0,0 @@
|
|
1
|
-
import "dotenv/config";
|
2
|
-
import type { SkillGroup } from "@xmtp/message-kit";
|
3
|
-
import OpenAI from "openai";
|
4
|
-
const openai = new OpenAI({
|
5
|
-
apiKey: process.env.OPEN_AI_API_KEY,
|
6
|
-
});
|
7
|
-
|
8
|
-
type ChatHistoryEntry = { role: string; content: string };
|
9
|
-
type ChatHistories = Record<string, ChatHistoryEntry[]>;
|
10
|
-
// New ChatMemory class
|
11
|
-
class ChatMemory {
|
12
|
-
private histories: ChatHistories = {};
|
13
|
-
|
14
|
-
getHistory(address: string): ChatHistoryEntry[] {
|
15
|
-
return this.histories[address] || [];
|
16
|
-
}
|
17
|
-
|
18
|
-
addEntry(address: string, entry: ChatHistoryEntry) {
|
19
|
-
if (!this.histories[address]) {
|
20
|
-
this.histories[address] = [];
|
21
|
-
}
|
22
|
-
this.histories[address].push(entry);
|
23
|
-
}
|
24
|
-
|
25
|
-
initializeWithSystem(address: string, systemPrompt: string) {
|
26
|
-
if (this.getHistory(address).length === 0) {
|
27
|
-
this.addEntry(address, {
|
28
|
-
role: "system",
|
29
|
-
content: systemPrompt,
|
30
|
-
});
|
31
|
-
}
|
32
|
-
}
|
33
|
-
|
34
|
-
clear() {
|
35
|
-
this.histories = {};
|
36
|
-
}
|
37
|
-
}
|
38
|
-
|
39
|
-
// Create singleton instance
|
40
|
-
export const chatMemory = new ChatMemory();
|
41
|
-
|
42
|
-
export const clearMemory = () => {
|
43
|
-
chatMemory.clear();
|
44
|
-
};
|
45
|
-
|
46
|
-
export const PROMPT_RULES = `You are a helpful and playful agent called {NAME} that lives inside a web3 messaging app called Converse.
|
47
|
-
- You can respond with multiple messages if needed. Each message should be separated by a newline character.
|
48
|
-
- You can trigger skills by only sending the command in a newline message.
|
49
|
-
- Never announce actions without using a command separated by a newline character.
|
50
|
-
- Dont answer in markdown format, just answer in plaintext.
|
51
|
-
- Do not make guesses or assumptions
|
52
|
-
- Only answer if the verified information is in the prompt.
|
53
|
-
- Check that you are not missing a command
|
54
|
-
- Focus only on helping users with operations detailed below.
|
55
|
-
`;
|
56
|
-
|
57
|
-
export function PROMPT_SKILLS_AND_EXAMPLES(skills: SkillGroup[], tag: string) {
|
58
|
-
let foundSkills = skills.filter(
|
59
|
-
(skill) => skill.tag == `@${tag.toLowerCase()}`,
|
60
|
-
);
|
61
|
-
if (!foundSkills.length || !foundSkills[0] || !foundSkills[0].skills)
|
62
|
-
return "";
|
63
|
-
let returnPrompt = `\nCommands:\n${foundSkills[0].skills
|
64
|
-
.map((skill) => skill.command)
|
65
|
-
.join("\n")}\n\nExamples:\n${foundSkills[0].skills
|
66
|
-
.map((skill) => skill.examples)
|
67
|
-
.join("\n")}`;
|
68
|
-
return returnPrompt;
|
69
|
-
}
|
70
|
-
|
71
|
-
export async function textGeneration(
|
72
|
-
memoryKey: string,
|
73
|
-
userPrompt: string,
|
74
|
-
systemPrompt: string,
|
75
|
-
) {
|
76
|
-
if (!memoryKey) {
|
77
|
-
clearMemory();
|
78
|
-
}
|
79
|
-
let messages = chatMemory.getHistory(memoryKey);
|
80
|
-
chatMemory.initializeWithSystem(memoryKey, systemPrompt);
|
81
|
-
if (messages.length === 0) {
|
82
|
-
messages.push({
|
83
|
-
role: "system",
|
84
|
-
content: systemPrompt,
|
85
|
-
});
|
86
|
-
}
|
87
|
-
messages.push({
|
88
|
-
role: "user",
|
89
|
-
content: userPrompt,
|
90
|
-
});
|
91
|
-
try {
|
92
|
-
const response = await openai.chat.completions.create({
|
93
|
-
model: "gpt-4o",
|
94
|
-
messages: messages as any,
|
95
|
-
});
|
96
|
-
const reply = response.choices[0].message.content;
|
97
|
-
messages.push({
|
98
|
-
role: "assistant",
|
99
|
-
content: reply || "No response from OpenAI.",
|
100
|
-
});
|
101
|
-
const cleanedReply = parseMarkdown(reply as string);
|
102
|
-
chatMemory.addEntry(memoryKey, {
|
103
|
-
role: "assistant",
|
104
|
-
content: cleanedReply,
|
105
|
-
});
|
106
|
-
return { reply: cleanedReply, history: messages };
|
107
|
-
} catch (error) {
|
108
|
-
console.error("Failed to fetch from OpenAI:", error);
|
109
|
-
throw error;
|
110
|
-
}
|
111
|
-
}
|
112
|
-
|
113
|
-
export async function processMultilineResponse(
|
114
|
-
memoryKey: string,
|
115
|
-
reply: string,
|
116
|
-
context: any,
|
117
|
-
) {
|
118
|
-
if (!memoryKey) {
|
119
|
-
clearMemory();
|
120
|
-
}
|
121
|
-
let messages = reply
|
122
|
-
.split("\n")
|
123
|
-
.map((message: string) => parseMarkdown(message))
|
124
|
-
.filter((message): message is string => message.length > 0);
|
125
|
-
|
126
|
-
console.log(messages);
|
127
|
-
for (const message of messages) {
|
128
|
-
if (message.startsWith("/")) {
|
129
|
-
const response = await context.executeSkill(message);
|
130
|
-
if (response && typeof response.message === "string") {
|
131
|
-
let msg = parseMarkdown(response.message);
|
132
|
-
chatMemory.addEntry(memoryKey, {
|
133
|
-
role: "system",
|
134
|
-
content: msg,
|
135
|
-
});
|
136
|
-
await context.send(response.message);
|
137
|
-
}
|
138
|
-
} else {
|
139
|
-
await context.send(message);
|
140
|
-
}
|
141
|
-
}
|
142
|
-
}
|
143
|
-
export function parseMarkdown(message: string) {
|
144
|
-
let trimmedMessage = message;
|
145
|
-
// Remove bold and underline markdown
|
146
|
-
trimmedMessage = trimmedMessage?.replace(/(\*\*|__)(.*?)\1/g, "$2");
|
147
|
-
// Remove markdown links, keeping only the URL
|
148
|
-
trimmedMessage = trimmedMessage?.replace(/\[([^\]]+)\]\(([^)]+)\)/g, "$2");
|
149
|
-
// Remove markdown headers
|
150
|
-
trimmedMessage = trimmedMessage?.replace(/^#+\s*(.*)$/gm, "$1");
|
151
|
-
// Remove inline code formatting
|
152
|
-
trimmedMessage = trimmedMessage?.replace(/`([^`]+)`/g, "$1");
|
153
|
-
// Remove single backticks at the start or end of the message
|
154
|
-
trimmedMessage = trimmedMessage?.replace(/^`|`$/g, "");
|
155
|
-
// Remove leading and trailing whitespace
|
156
|
-
trimmedMessage = trimmedMessage?.replace(/^\s+|\s+$/g, "");
|
157
|
-
// Remove any remaining leading or trailing whitespace
|
158
|
-
trimmedMessage = trimmedMessage.trim();
|
159
|
-
|
160
|
-
return trimmedMessage;
|
161
|
-
}
|
@@ -1,174 +0,0 @@
|
|
1
|
-
import dotenv from "dotenv";
|
2
|
-
dotenv.config();
|
3
|
-
import type { SkillGroup } from "@xmtp/message-kit";
|
4
|
-
import OpenAI from "openai";
|
5
|
-
const openai = new OpenAI({
|
6
|
-
apiKey: process.env.OPEN_AI_API_KEY,
|
7
|
-
});
|
8
|
-
|
9
|
-
export type ChatHistoryEntry = { role: string; content: string };
|
10
|
-
export type ChatHistories = Record<string, ChatHistoryEntry[]>;
|
11
|
-
|
12
|
-
// New ChatMemory class
|
13
|
-
class ChatMemory {
|
14
|
-
private histories: ChatHistories = {};
|
15
|
-
|
16
|
-
getHistory(address: string): ChatHistoryEntry[] {
|
17
|
-
return this.histories[address] || [];
|
18
|
-
}
|
19
|
-
|
20
|
-
addEntry(address: string, entry: ChatHistoryEntry) {
|
21
|
-
if (!this.histories[address]) {
|
22
|
-
this.histories[address] = [];
|
23
|
-
}
|
24
|
-
this.histories[address].push(entry);
|
25
|
-
}
|
26
|
-
|
27
|
-
initializeWithSystem(address: string, systemPrompt: string) {
|
28
|
-
if (this.getHistory(address).length === 0) {
|
29
|
-
this.addEntry(address, {
|
30
|
-
role: "system",
|
31
|
-
content: systemPrompt,
|
32
|
-
});
|
33
|
-
}
|
34
|
-
}
|
35
|
-
|
36
|
-
clear() {
|
37
|
-
this.histories = {};
|
38
|
-
}
|
39
|
-
}
|
40
|
-
|
41
|
-
export const clearMemory = () => {
|
42
|
-
chatHistories = {};
|
43
|
-
};
|
44
|
-
|
45
|
-
// Create singleton instance
|
46
|
-
export const chatMemory = new ChatMemory();
|
47
|
-
|
48
|
-
let chatHistories: ChatHistories = {};
|
49
|
-
export const PROMPT_RULES = `You are a helpful and playful agent called {NAME} that lives inside a web3 messaging app called Converse.
|
50
|
-
- You can respond with multiple messages if needed. Each message should be separated by a newline character.
|
51
|
-
- You can trigger skills by only sending the command in a newline message.
|
52
|
-
- Never announce actions without using a command separated by a newline character.
|
53
|
-
- Dont answer in markdown format, just answer in plaintext.
|
54
|
-
- Do not make guesses or assumptions
|
55
|
-
- Only answer if the verified information is in the prompt.
|
56
|
-
- Check that you are not missing a command
|
57
|
-
- Focus only on helping users with operations detailed below.
|
58
|
-
`;
|
59
|
-
|
60
|
-
export const PROMPT_SKILLS_AND_EXAMPLES = (skills: SkillGroup[]) => `
|
61
|
-
Commands:
|
62
|
-
${skills
|
63
|
-
.map((skill) => skill.skills.map((s) => s.command).join("\n"))
|
64
|
-
.join("\n")}
|
65
|
-
|
66
|
-
Examples:
|
67
|
-
${skills
|
68
|
-
.map((skill) => skill.skills.map((s) => s.examples).join("\n"))
|
69
|
-
.join("\n")}
|
70
|
-
`;
|
71
|
-
|
72
|
-
export async function agentResponse(
|
73
|
-
sender: { address: string },
|
74
|
-
userPrompt: string,
|
75
|
-
systemPrompt: string,
|
76
|
-
context: any,
|
77
|
-
) {
|
78
|
-
try {
|
79
|
-
const { reply } = await textGeneration(
|
80
|
-
sender.address,
|
81
|
-
userPrompt,
|
82
|
-
systemPrompt,
|
83
|
-
);
|
84
|
-
await processMultilineResponse(sender.address, reply, context);
|
85
|
-
} catch (error) {
|
86
|
-
console.error("Error during OpenAI call:", error);
|
87
|
-
await context.reply("An error occurred while processing your request.");
|
88
|
-
}
|
89
|
-
}
|
90
|
-
export async function textGeneration(
|
91
|
-
address: string,
|
92
|
-
userPrompt: string,
|
93
|
-
systemPrompt: string,
|
94
|
-
) {
|
95
|
-
let messages = chatMemory.getHistory(address);
|
96
|
-
chatMemory.initializeWithSystem(address, systemPrompt);
|
97
|
-
if (messages.length === 0) {
|
98
|
-
messages.push({
|
99
|
-
role: "system",
|
100
|
-
content: systemPrompt,
|
101
|
-
});
|
102
|
-
}
|
103
|
-
messages.push({
|
104
|
-
role: "user",
|
105
|
-
content: userPrompt,
|
106
|
-
});
|
107
|
-
try {
|
108
|
-
const response = await openai.chat.completions.create({
|
109
|
-
model: "gpt-4o",
|
110
|
-
messages: messages as any,
|
111
|
-
});
|
112
|
-
const reply = response.choices[0].message.content;
|
113
|
-
messages.push({
|
114
|
-
role: "assistant",
|
115
|
-
content: reply || "No response from OpenAI.",
|
116
|
-
});
|
117
|
-
const cleanedReply = parseMarkdown(reply as string);
|
118
|
-
chatMemory.addEntry(address, {
|
119
|
-
role: "assistant",
|
120
|
-
content: cleanedReply,
|
121
|
-
});
|
122
|
-
return { reply: cleanedReply, history: messages };
|
123
|
-
} catch (error) {
|
124
|
-
console.error("Failed to fetch from OpenAI:", error);
|
125
|
-
throw error;
|
126
|
-
}
|
127
|
-
}
|
128
|
-
|
129
|
-
export async function processMultilineResponse(
|
130
|
-
address: string,
|
131
|
-
reply: string,
|
132
|
-
context: any,
|
133
|
-
) {
|
134
|
-
let messages = reply
|
135
|
-
.split("\n")
|
136
|
-
.map((message: string) => parseMarkdown(message))
|
137
|
-
.filter((message): message is string => message.length > 0);
|
138
|
-
|
139
|
-
console.log(messages);
|
140
|
-
for (const message of messages) {
|
141
|
-
if (message.startsWith("/")) {
|
142
|
-
const response = await context.skill(message);
|
143
|
-
if (response && typeof response.message === "string") {
|
144
|
-
let msg = parseMarkdown(response.message);
|
145
|
-
chatMemory.addEntry(address, {
|
146
|
-
role: "system",
|
147
|
-
content: msg,
|
148
|
-
});
|
149
|
-
await context.send(response.message);
|
150
|
-
}
|
151
|
-
} else {
|
152
|
-
await context.send(message);
|
153
|
-
}
|
154
|
-
}
|
155
|
-
}
|
156
|
-
export function parseMarkdown(message: string) {
|
157
|
-
let trimmedMessage = message;
|
158
|
-
// Remove bold and underline markdown
|
159
|
-
trimmedMessage = trimmedMessage?.replace(/(\*\*|__)(.*?)\1/g, "$2");
|
160
|
-
// Remove markdown links, keeping only the URL
|
161
|
-
trimmedMessage = trimmedMessage?.replace(/\[([^\]]+)\]\(([^)]+)\)/g, "$2");
|
162
|
-
// Remove markdown headers
|
163
|
-
trimmedMessage = trimmedMessage?.replace(/^#+\s*(.*)$/gm, "$1");
|
164
|
-
// Remove inline code formatting
|
165
|
-
trimmedMessage = trimmedMessage?.replace(/`([^`]+)`/g, "$1");
|
166
|
-
// Remove single backticks at the start or end of the message
|
167
|
-
trimmedMessage = trimmedMessage?.replace(/^`|`$/g, "");
|
168
|
-
// Remove leading and trailing whitespace
|
169
|
-
trimmedMessage = trimmedMessage?.replace(/^\s+|\s+$/g, "");
|
170
|
-
// Remove any remaining leading or trailing whitespace
|
171
|
-
trimmedMessage = trimmedMessage.trim();
|
172
|
-
|
173
|
-
return trimmedMessage;
|
174
|
-
}
|