- Bots get continue_in_new_session: the bot writes a title and summary, the session closes for good (read-only) and the new one opens with the summary as a "Carried over from the last session" message that links back to the old session. - Continue in new session (conversation menu, sessions modal) and the automatic rollover at the session length do the same; New session now starts a fresh, unlinked session. - Session length is an app setting in Settings > General. - ?session_id= opens a session; a carried-over one shows a bar linking to where the conversation went on instead of the composer. - The thread can open the previous session above the current one (shown only, never in the prompt), and replies get search_past_sessions and read_past_session. - Sessions are named from their opening messages, not their latest, and a carried summary is labelled as the earlier session's. Co-Authored-By: Claude Opus 5.5 <[email protected]>
107 lines
3.8 KiB
TypeScript
107 lines
3.8 KiB
TypeScript
import { AppData } from "@/src/data/app-data";
|
|
import type { ConversationHistory } from "@/src/types";
|
|
import grabActiveBotTask from "../bots/grab-active-bot-task";
|
|
import grabBotMessages from "../bots/grab-bot-messages";
|
|
import ensureBotSession from "./ensure-bot-session";
|
|
import grabCarriedToSessionId from "./grab-carried-to-session-id";
|
|
import reopenBotSession from "./reopen-bot-session";
|
|
import grabUserBotSession from "./grab-user-bot-session";
|
|
import grabUserConversation from "./grab-user-conversation";
|
|
import markBotSessionRead from "./mark-bot-session-read";
|
|
|
|
type Params = {
|
|
user_id: number;
|
|
bot_id: number | string;
|
|
/**
|
|
* The workspace the conversation is in; none for the bot's own chat.
|
|
*/
|
|
workspace_id?: number | string | null;
|
|
/**
|
|
* A session of the conversation to show instead of the active one
|
|
* (the page's `?session_id=`). One that isn't the user's, or is in
|
|
* another conversation, is ignored.
|
|
*/
|
|
session_id?: number | string | null;
|
|
};
|
|
|
|
/**
|
|
* A conversation's history, which the conversation pages load on the
|
|
* client once they render (`api/admin/bots/conversation-history`): the
|
|
* bot's active session there, or the one asked for (marked read; a closed
|
|
* one is reopened, unless it was carried over, which only shows, with
|
|
* where the conversation went on), its latest
|
|
* `AppData.ConversationFirstMessages` messages (the thread loads older
|
|
* ones as it scrolls) and the bot's active task in it. Everything else on
|
|
* the page comes with it from the server (`grabConversationProps`).
|
|
* Null when the user can't chat with the bot there.
|
|
*/
|
|
export default async function grabConversationHistory({
|
|
user_id,
|
|
bot_id,
|
|
workspace_id,
|
|
session_id,
|
|
}: Params): Promise<ConversationHistory | null> {
|
|
const conversation = await grabUserConversation({ user_id, bot_id, workspace_id }).catch(
|
|
() => null,
|
|
);
|
|
|
|
if (!conversation?.bot?.id) return null;
|
|
|
|
const open_bot_id = conversation.bot.id;
|
|
const conversation_workspace_id = conversation.workspace_id || null;
|
|
|
|
const asked = session_id
|
|
? await grabUserBotSession({ session_id, user_id })
|
|
: null;
|
|
|
|
const in_conversation =
|
|
asked?.id &&
|
|
Number(asked.bot_id) == Number(open_bot_id) &&
|
|
(asked.workspace_id ? Number(asked.workspace_id) : null) ==
|
|
(conversation_workspace_id ? Number(conversation_workspace_id) : null);
|
|
|
|
/**
|
|
* A closed session asked for is reopened, as clicking it in a list
|
|
* does, unless it was carried over into a newer one: that one only
|
|
* shows, with the way to where the conversation went on.
|
|
*/
|
|
const carried_to =
|
|
in_conversation && asked.status != "active"
|
|
? await grabCarriedToSessionId({ session_id: asked.id!, user_id })
|
|
: null;
|
|
|
|
const session = !in_conversation
|
|
? await ensureBotSession({
|
|
user_id,
|
|
bot_id: open_bot_id,
|
|
workspace_id: conversation.workspace_id,
|
|
})
|
|
: asked.status == "active" || carried_to
|
|
? asked
|
|
: await reopenBotSession({ session_id: asked.id!, user_id });
|
|
|
|
if (session.unread) {
|
|
await markBotSessionRead({ session_id: session.id!, user_id });
|
|
session.unread = 0;
|
|
}
|
|
|
|
const [messages, task] = await Promise.all([
|
|
grabBotMessages({
|
|
session_id: session.id!,
|
|
user_id,
|
|
limit: AppData.ConversationFirstMessages + 1,
|
|
}),
|
|
grabActiveBotTask({ bot_id: open_bot_id, session_id: session.id }),
|
|
]);
|
|
|
|
const has_more = messages.length > AppData.ConversationFirstMessages;
|
|
|
|
return {
|
|
session,
|
|
messages: has_more ? messages.slice(1) : messages,
|
|
has_more,
|
|
task,
|
|
moved_to_session_id: carried_to,
|
|
};
|
|
}
|