Trim page props and page the conversation's messages

Bot and workspace lists in page props leave out instructions, memory and
workspace context, and carry the last message as a short preview. The
header avatar's edit form loads the bot's instructions when it opens.
The conversation renders its latest 30 messages and loads older ones as
the thread scrolls to its top.

Also: the composer shows a placeholder until its editor loads, and
`bun start` no longer builds first.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
2026-10-20 20:09:01 +01:00
co-authored by Claude Opus 5.5
parent b3057119df
commit f13fa863c5
30 changed files with 583 additions and 45 deletions
@@ -0,0 +1,47 @@
import userAuth from "@/src/functions/backend/auth/user-auth";
import grabUserBot from "@/src/functions/backend/db/bots/grab-user-bot";
import { BotIdRequestSchema } from "@/src/schemas/bot-schema";
import AppError from "@/src/utils/app-error";
import parseWithSchema from "@/src/utils/parse-with-schema";
import canManageCrew from "@/src/utils/rbac/can-manage-crew";
import safeErrorMessage from "@/src/utils/safe-error-message";
import type {
APIResponseObject,
BunextAPIRouteHandler,
} from "@moduletrace/bunext/types";
/**
* A bot's core instructions, for its edit form in the conversation, which
* loads them when it opens (page props leave them out). For super admins
* and admins; only the super admin reaches the coordinator.
*/
export const handler: BunextAPIRouteHandler<
APIResponseObject<{ system_prompt: string }>
> = async ({ req, body }) => {
try {
if (req.method != "POST") {
throw new AppError(`Method not allowed`);
}
const { user, user_types } = await userAuth({ req });
if (!user?.logged_in_status || !user.id) {
return { success: false, msg: `Unauthorized`, logoutUser: true };
}
if (!canManageCrew({ user_types })) {
throw new AppError(`Only an admin can edit a bot.`);
}
const { bot_id } = parseWithSchema({ schema: BotIdRequestSchema, data: body });
const bot = await grabUserBot({ bot_id, user_id: user.id });
if (!bot?.id) {
throw new AppError(`Bot not found.`);
}
return { success: true, singleRes: { system_prompt: bot.system_prompt || "" } };
} catch (error: unknown) {
return { success: false, msg: safeErrorMessage({ error }) };
}
};
@@ -0,0 +1,60 @@
import userAuth from "@/src/functions/backend/auth/user-auth";
import grabUserBotSession from "@/src/functions/backend/db/bot-sessions/grab-user-bot-session";
import grabBotMessages from "@/src/functions/backend/db/bots/grab-bot-messages";
import { AppData } from "@/src/data/app-data";
import { OlderBotMessagesRequestSchema } from "@/src/schemas/bot-schema";
import type { OlderBotMessagesData } from "@/src/types";
import AppError from "@/src/utils/app-error";
import parseWithSchema from "@/src/utils/parse-with-schema";
import safeErrorMessage from "@/src/utils/safe-error-message";
import type {
APIResponseObject,
BunextAPIRouteHandler,
} from "@moduletrace/bunext/types";
/**
* The messages before `before_id` in one of the session user's own
* sessions, `AppData.ConversationOlderMessages` at a time, for the thread
* scrolled to its top.
*/
export const handler: BunextAPIRouteHandler<
APIResponseObject<OlderBotMessagesData>
> = async ({ req, body }) => {
try {
if (req.method != "POST") {
throw new AppError(`Method not allowed`);
}
const { user } = await userAuth({ req });
if (!user?.logged_in_status || !user.id) {
return { success: false, msg: `Unauthorized`, logoutUser: true };
}
const { session_id, before_id } = parseWithSchema({
schema: OlderBotMessagesRequestSchema,
data: body,
});
const session = await grabUserBotSession({ session_id, user_id: user.id });
if (!session?.id) {
throw new AppError(`Session not found.`);
}
const messages = await grabBotMessages({
session_id: session.id,
before_id,
limit: AppData.ConversationOlderMessages + 1,
user_id: user.id,
});
const has_more = messages.length > AppData.ConversationOlderMessages;
return {
success: true,
singleRes: { messages: has_more ? messages.slice(1) : messages, has_more },
};
} catch (error: unknown) {
return { success: false, msg: safeErrorMessage({ error }) };
}
};
@@ -12,6 +12,7 @@ import type {
APIResponseObject,
BunextAPIRouteHandler,
} from "@moduletrace/bunext/types";
import railBots from "@/src/utils/rail-bots";
/**
* The crew's workers that aren't in a workspace yet, for the workspace
@@ -48,9 +49,11 @@ export const handler: BunextAPIRouteHandler<APIResponseObject<BotWithLastMessage
return {
success: true,
payload: bots.filter(
(bot) => bot.kind != "coordinator" && !members.some((member) => member.id == bot.id),
),
payload: railBots({
bots: bots.filter(
(bot) => bot.kind != "coordinator" && !members.some((member) => member.id == bot.id),
),
}),
};
} catch (error: unknown) {
return { success: false, msg: safeErrorMessage({ error }) };