Add replies and emoji reactions to chat messages

Every message has a row under it to reply or react. Replying quotes the
message above the composer, and the sent message stores
reply_to_message_id (a plain id, not a foreign key, so deleting the
quoted message only drops the quote). send-message accepts a quote from
any session of the same conversation, so a rollover or a thread that
moved on still sends; the conversation drops a picked quote when its
session changes. The bot reads the quote as "[Replying to ...]" before
the user's turn, file-only replies included, and relayed messages carry
it too.

Reactions are a fixed set (BotMessageReactions) in
bot_message_reactions, one per message, emoji and user or bot. Users
toggle their own through api/admin/bots/react-message, and every bot
gets react_to_message for the session it answers (the user's latest
message by default). Both push the fresh list as server:bot-reaction,
with mine worked out for the session's user.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
2026-10-19 21:56:31 +01:00
co-authored by Claude Opus 5.5
parent bc499a7466
commit d1b5b6d68a
44 changed files with 1289 additions and 58 deletions
@@ -0,0 +1,18 @@
import fetchApi from "@moduletrace/twui/utils/fetch/fetchApi";
import type { APIResponseObject } from "@moduletrace/bunext/types";
import type { ReactToBotMessageRequest } from "@/src/schemas/bot-schema";
import type { BotMessageReactionData } from "@/src/types";
/**
* Adds or takes back an emoji reaction on a message, returning the
* message's fresh reactions.
*/
export default async function reactToBotMessage({ message_id, emoji }: ReactToBotMessageRequest) {
return await fetchApi<
ReactToBotMessageRequest,
APIResponseObject<BotMessageReactionData>
>(`/api/admin/bots/react-message`, {
method: "POST",
body: { message_id, emoji },
});
}
@@ -8,12 +8,13 @@ export default async function sendBotMessage({
workspace_id,
text,
media_ids,
reply_to_message_id,
}: SendBotMessageRequest) {
return await fetchApi<
SendBotMessageRequest,
APIResponseObject<BotMessageWithAttachments>
>(`/api/admin/bots/send-message`, {
method: "POST",
body: { bot_id, workspace_id, text, media_ids },
body: { bot_id, workspace_id, text, media_ids, reply_to_message_id },
});
}