|
| 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