forked from xmtplabs/xmtp-agent-examples
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.ts
More file actions
272 lines (225 loc) · 7.7 KB
/
Copy pathindex.ts
File metadata and controls
272 lines (225 loc) · 7.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
import { Agent, getTestUrl, type MessageContext } from "@xmtp/agent-sdk";
import { ActionStyle } from "@xmtp/node-sdk";
import {
inlineActionsMiddleware,
registerAction,
ActionBuilder,
sendConfirmation,
} from "../../utils/inline-actions";
import { loadEnvFile } from "../../utils/general";
loadEnvFile();
// Store inventory
interface Product {
id: string;
name: string;
category: string;
emoji: string;
}
const products: Product[] = [
// Personal Care
{
id: "deodorant",
name: "Deodorant",
category: "personal-care",
emoji: "🧴",
},
{
id: "toothbrush",
name: "Toothbrush",
category: "personal-care",
emoji: "🪥",
},
{
id: "toothpaste",
name: "Toothpaste",
category: "personal-care",
emoji: "🦷",
},
{ id: "tictacs", name: "Tic Tacs", category: "personal-care", emoji: "🍬" },
// Beverages
{ id: "redbull", name: "Red Bull", category: "beverages", emoji: "🔴" },
];
// Track orders per conversation
const orders = new Map<string, Product[]>();
// Hackathon prize information in markdown format
const hackathonPrizesMarkdown = `
## Say hi to XMTP!
XMTP is the largest & most secure decentralized messaging network. Powers a rapidly growing ecosystem of mini apps—where everything is a built-in chat experience from trading, prediction markets, event coordination, payments, and games.
## 🏆 Hackathon prizes
#### 📲 Best Miniapp in a Group Chat
- **$2500** x 1 team
#### 🤖 Best Use of the Agent SDK
- **$2500** x 1 team
---
📋 **[Full Prize Breakdown](https://ethglobal.com/events/buenosaires/prizes/xmtp)**`;
function getOrderSummary(conversationId: string): string {
const orderItems = orders.get(conversationId) || [];
if (orderItems.length === 0) {
return "Your cart is empty.";
}
const itemCounts = new Map<string, number>();
orderItems.forEach((item) => {
itemCounts.set(item.id, (itemCounts.get(item.id) || 0) + 1);
});
const summary = Array.from(itemCounts.entries())
.map(([id, count]) => {
const product = products.find((p) => p.id === id);
return `${product?.emoji} ${product?.name} x${count}`;
})
.join("\n");
return `Your order:\n${summary}`;
}
const dbPath = (inboxId: string) => {
const filename = `${process.env.XMTP_ENV}-${inboxId.slice(0, 8)}.db3`;
const fullpath = process.env.RAILWAY_VOLUME_MOUNT_PATH
? `${process.env.RAILWAY_VOLUME_MOUNT_PATH}/${filename}`
: `./${filename}`;
console.log("dbPath", fullpath);
return fullpath;
};
const agent = await Agent.createFromEnv({
dbPath: dbPath,
});
// Register action handlers
registerAction("show-menu", async (ctx: MessageContext) => {
const builder = ActionBuilder.create(
"main-menu",
"🏪 Welcome to General Store!\n\nSelect a product:",
);
// Add all products to the menu
products.forEach((product) => {
builder.add(`add-${product.id}`, `${product.emoji} ${product.name}`);
});
// Add cart and checkout options
builder.add("view-cart", "🛒 View Cart");
builder.add("checkout", "✅ Checkout");
await ctx.conversation.sendActions(builder.build());
});
// Register add-to-cart actions for each product
products.forEach((product) => {
registerAction(`add-${product.id}`, async (ctx: MessageContext) => {
const conversationId = ctx.conversation.id;
const currentOrder = orders.get(conversationId) || [];
currentOrder.push(product);
orders.set(conversationId, currentOrder);
await ctx.conversation.sendText(
`✅ Added ${product.emoji} ${product.name} to your cart!\n\n${getOrderSummary(conversationId)}`,
);
//1
// Show navigation options
const navMenu = ActionBuilder.create(
"after-add-menu",
"What would you like to do next?",
)
.add("show-menu", "🛍️ Continue Shopping")
.add("view-cart", "🛒 View Cart")
.add("checkout", "✅ Checkout")
.build();
await ctx.conversation.sendActions(navMenu);
});
});
registerAction("view-cart", async (ctx: MessageContext) => {
const conversationId = ctx.conversation.id;
const summary = getOrderSummary(conversationId);
const menu = ActionBuilder.create("cart-menu", summary)
.add("show-menu", "🛍️ Continue Shopping")
.add("checkout", "✅ Checkout")
.add("clear-cart", "🗑️ Clear Cart", ActionStyle.Danger)
.build();
await ctx.conversation.sendActions(menu);
});
registerAction("clear-cart", async (ctx: MessageContext) => {
await sendConfirmation(
ctx,
"Are you sure you want to clear your cart?",
async (ctx: MessageContext) => {
const conversationId = ctx.conversation.id;
orders.delete(conversationId);
await ctx.conversation.sendText("🗑️ Cart cleared!");
const menu = ActionBuilder.create(
"after-clear-menu",
"Your cart has been cleared. What would you like to do?",
)
.add("show-menu", "🛍️ Start Shopping")
.build();
await ctx.conversation.sendActions(menu);
},
);
});
registerAction("checkout", async (ctx: MessageContext) => {
const conversationId = ctx.conversation.id;
const orderItems = orders.get(conversationId) || [];
if (orderItems.length === 0) {
await ctx.conversation.sendText(
"🛒 Your cart is empty! Add some items first.",
);
const menu = ActionBuilder.create(
"empty-cart-menu",
"What would you like to do?",
)
.add("show-menu", "🛍️ Start Shopping")
.build();
await ctx.conversation.sendActions(menu);
return;
}
const summary = getOrderSummary(conversationId);
await sendConfirmation(
ctx,
`Confirm your order?\n\n${summary}\n\nThis will place your order.`,
async (ctx: MessageContext) => {
const conversationId = ctx.conversation.id;
const orderItems = orders.get(conversationId) || [];
const itemCounts = new Map<string, number>();
orderItems.forEach((item) => {
itemCounts.set(item.id, (itemCounts.get(item.id) || 0) + 1);
});
const orderDetails = Array.from(itemCounts.entries())
.map(([id, count]) => {
const product = products.find((p) => p.id === id);
return `${product?.emoji} ${product?.name} x${count}`;
})
.join("\n");
await ctx.conversation.sendText(
`✅ Order confirmed!\n\n${orderDetails}\n\n📦 Your order will be ready for pickup soon. Thank you for shopping at General Store!`,
);
// Send hackathon prize information as markdown
await ctx.conversation.sendMarkdown(hackathonPrizesMarkdown);
// Clear the cart after checkout
orders.delete(conversationId);
const menu = ActionBuilder.create(
"after-checkout-menu",
"Would you like to place another order?",
)
.add("show-menu", "🛍️ New Order")
.build();
await ctx.conversation.sendActions(menu);
},
);
});
// Use the inline actions middleware
agent.use(inlineActionsMiddleware);
// Handle text messages - show menu on any text
agent.on("text", async (ctx) => {
console.log("text", ctx);
const builder = ActionBuilder.create(
"main-menu",
"🏪 Welcome to General Store!\n\nSelect a product:",
);
// Add all products to the menu
products.forEach((product) => {
builder.add(`add-${product.id}`, `${product.emoji} ${product.name}`);
});
// Add cart and checkout options
builder.add("view-cart", "🛒 View Cart");
builder.add("checkout", "✅ Checkout");
await ctx.conversation.sendActions(builder.build());
});
// Handle startup
agent.on("start", () => {
console.log(`🏪 General Store Agent is running...`);
console.log(`Address: ${agent.address}`);
console.log(`🔗 ${getTestUrl(agent.client)}`);
console.log(`Send any message to start shopping!`);
});
// Start the agent
await agent.start();