Skip to content

Commit efc3411

Browse files
committed
Recipes
1 parent f3afb3d commit efc3411

File tree

3 files changed

+187
-1
lines changed

3 files changed

+187
-1
lines changed

docs/.vitepress/config.mts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,15 @@ export default defineConfig({
5151
{ text: "About", link: "/intro.md" },
5252
{ text: "Start", link: "/start.md" },
5353
concepts,
54+
{ text: "Recipes", link: "/recipes.md" },
5455
{ text: "Examples", link: "/examples.md" },
5556
],
5657

5758
sidebar: [
5859
{ text: "What is BotKit?", link: "/intro.md" },
5960
{ text: "Getting started", link: "/start.md" },
6061
concepts,
62+
{ text: "Recipes", link: "/recipes.md" },
6163
{ text: "Examples", link: "/examples.md" },
6264
{ text: "Changelog", link: "/changelog.md" },
6365
],

docs/concepts/message.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,7 @@ property recursively:
324324

325325
~~~~ typescript
326326
bot.onReply = async (session, reply) => {
327-
let message: Message | undefined = reply;
327+
let message: Message<MessageClass, void> | undefined = reply;
328328
while (message != null) {
329329
console.log(message);
330330
message = message.replyTarget;

docs/recipes.md

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
---
2+
description: >-
3+
The recipes section contains a list of recipes that demonstrate how to
4+
implement common tasks with BotKit.
5+
---
6+
7+
Recipes
8+
=======
9+
10+
The recipes section contains a list of recipes that demonstrate how to implement
11+
common tasks with BotKit.
12+
13+
14+
Sending a direct message
15+
------------------------
16+
17+
It is very simple to send a direct message to a user: set
18+
the [`visibility`](./concepts/message.md#visibility) option to `"direct"`
19+
when calling the [`Session.publish()`](./concepts/message.md#publishing-a-message)
20+
method:
21+
22+
~~~~ typescript
23+
bot.onMention = async (session, message) => {
24+
await session.publish(
25+
text`Hi, ${message.actor}!`,
26+
{ visibility: "direct" },
27+
);
28+
};
29+
~~~~
30+
31+
> [!CAUTION]
32+
> You need to mention at least one actor in the message to send a direct
33+
> message. Otherwise, the message won't be read by anyone.
34+
35+
36+
Following back
37+
--------------
38+
39+
To let your bot follow back all of its followers, you can use
40+
the [`onFollow`](./concepts/events.md#follow) event with
41+
the [`Session.follow()`](./concepts//session.md#following-an-actor) method
42+
together:
43+
44+
~~~~ typescript
45+
bot.onFollow = async (session, followRequest) => {
46+
await followRequest.accept();
47+
await session.follow(followRequest.follower);
48+
};
49+
~~~~
50+
51+
> [!NOTE]
52+
> It is not guaranteed that the follow request will be accepted.
53+
> The actor may reject your bot's follow request.
54+
55+
56+
Automatically deleting old messages
57+
-----------------------------------
58+
59+
To automatically delete old messages after a certain period, you can use
60+
[`Session.getOutbox()`](./concepts/message.md#getting-published-messages) method,
61+
[`AuthorizedMessage.delete()`](./concepts/message.md#deleting-a-message) method,
62+
and the [`setInterval()`] function together. The following example shows how to
63+
delete all messages older than a week:
64+
65+
~~~~ typescript
66+
async function deleteOldPosts(session: Session): Promise<void> {
67+
const now = Temporal.Now.instant();
68+
const oneWeekAgo = now.subtract({ hours: 7 * 24 });
69+
const oldPosts = session.getOutbox({ until: oneWeekAgo });
70+
for await (const post of oldPosts) {
71+
await post.delete();
72+
}
73+
}
74+
75+
setInterval(
76+
deleteOldPosts,
77+
1000 * 60 * 60,
78+
bot.getSession("https://yourdomain")
79+
);
80+
~~~~
81+
82+
[`setInterval()`]: https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setInterval
83+
84+
85+
Scheduled messages
86+
------------------
87+
88+
You can use the [`setInterval()`] function to send messages at regular
89+
intervals:
90+
91+
~~~~ typescript
92+
setInterval(async () => {
93+
const session = bot.getSession("https://yourdomain");
94+
await session.publish(text`Hello, world!`);
95+
}, 1000 * 60 * 60);
96+
~~~~
97+
98+
Or if you use non-standard APIs like [`Deno.cron()`], you can use it to send
99+
messages at specific times:
100+
101+
~~~~ typescript
102+
Deno.cron("scheduled messages", "0 0 12 * * *", async () => {
103+
const session = bot.getSession("https://yourdomain");
104+
await session.publish(text`Hello, world!`);
105+
});
106+
~~~~
107+
108+
[`Deno.cron()`]: https://docs.deno.com/api/deno/~/Deno.cron
109+
110+
111+
Automatically replying to mentions
112+
----------------------------------
113+
114+
It is simple to automatically reply to mentions of your bot. You can use the
115+
[`onMention`](./concepts/events.md#mention) event handler and
116+
the [`Message.reply()`](./concepts/message.md#replying-to-a-message) method
117+
together:
118+
119+
~~~~ typescript
120+
bot.onMention = async (session, message) => {
121+
await message.reply(text`You mentioned me, ${message.actor}!`);
122+
};
123+
~~~~
124+
125+
126+
Thread creation
127+
---------------
128+
129+
Although BotKit has no limitation on characters in a message, sometimes you may
130+
want to create a thread for storytelling or to make audience engagement easier.
131+
You can use the [`Message.reply()`](./concepts/message.md#replying-to-a-message)
132+
method to your own messages too:
133+
134+
~~~~ typescript
135+
async function *createThread<TContextData>(
136+
session: Session,
137+
messages: Text<"block", TContextData>[]
138+
): AsyncIterable<AuthorizedMessage<Note, TContextData>> {
139+
let parent = await session.publish(messages[0]);
140+
yield parent;
141+
for (let i = 1; i < messages.length; i++) {
142+
parent = await parent.reply(messages[i]);
143+
yield parent;
144+
}
145+
}
146+
147+
const messages = [
148+
text`Once upon a time, there was a bot named BotKit.`,
149+
text`BotKit was created by a developer who wanted to make a bot.`,
150+
text`The developer used BotKit to create a bot that could do anything.`,
151+
text`The bot was so powerful that it could even create other bots.`,
152+
text`And so, BotKit lived happily ever after.`,
153+
];
154+
const session = bot.getSession("https://yourdomain");
155+
for await (const message of createThread(session, messages)) {
156+
console.debug(`Created message ${message.id}`);
157+
}
158+
~~~~
159+
160+
161+
Thread traversal
162+
----------------
163+
164+
Suppose your bot is an LLM-based chatbot and you want to give your LLM model
165+
the previous messages in a thread as context. You can achieve this by
166+
recursively traversing
167+
the [`Message.replyTarget`](./concepts/message.md#traversing-the-conversation)
168+
property:
169+
170+
~~~~ typescript
171+
async function traverseThread<TContextData>(
172+
session: Session,
173+
message: Message<MessageClass, TContextData>
174+
): Promise<Message<MessageClass, TContextData>[]> {
175+
const thread: Message<MessageClass, TContextData>[] = [];
176+
let m: Message<MessageClass, TContextData> | undefined = message;
177+
while (m != null) {
178+
thread.push(m);
179+
m = m.replyTarget;
180+
}
181+
thread.reverse();
182+
return thread;
183+
}
184+
~~~~

0 commit comments

Comments
 (0)