|
|
const { multiUserMode, userFromSession, reqBody, safeJsonParse,} = require("../utils/http");const { validatedRequest } = require("../utils/middleware/validatedRequest");const { Telemetry } = require("../models/telemetry");const { flexUserRoleValid, ROLES,} = require("../utils/middleware/multiUserProtected");const { EventLogs } = require("../models/eventLogs");const { WorkspaceThread } = require("../models/workspaceThread");const { validWorkspaceSlug, validWorkspaceAndThreadSlug,} = require("../utils/middleware/validWorkspace");const { WorkspaceChats } = require("../models/workspaceChats");const { convertToChatHistory } = require("../utils/helpers/chat/responses");
function workspaceThreadEndpoints(app) { if (!app) return;
app.post( "/workspace/:slug/thread/new", [validatedRequest, flexUserRoleValid([ROLES.all]), validWorkspaceSlug], async (request, response) => { try { const user = await userFromSession(request, response); const workspace = response.locals.workspace; const { thread, message } = await WorkspaceThread.new( workspace, user?.id ); await Telemetry.sendTelemetry( "workspace_thread_created", { multiUserMode: multiUserMode(response), LLMSelection: process.env.LLM_PROVIDER || "openai", Embedder: process.env.EMBEDDING_ENGINE || "inherit", VectorDbSelection: process.env.VECTOR_DB || "lancedb", TTSSelection: process.env.TTS_PROVIDER || "native", }, user?.id );
await EventLogs.logEvent( "workspace_thread_created", { workspaceName: workspace?.name || "Unknown Workspace", }, user?.id ); response.status(200).json({ thread, message }); } catch (e) { console.error(e.message, e); response.sendStatus(500).end(); } } );
app.get( "/workspace/:slug/threads", [validatedRequest, flexUserRoleValid([ROLES.all]), validWorkspaceSlug], async (request, response) => { try { const user = await userFromSession(request, response); const workspace = response.locals.workspace; const threads = await WorkspaceThread.where({ workspace_id: workspace.id, user_id: user?.id || null, }); response.status(200).json({ threads }); } catch (e) { console.error(e.message, e); response.sendStatus(500).end(); } } );
app.delete( "/workspace/:slug/thread/:threadSlug", [ validatedRequest, flexUserRoleValid([ROLES.all]), validWorkspaceAndThreadSlug, ], async (_, response) => { try { const thread = response.locals.thread; await WorkspaceThread.delete({ id: thread.id }); response.sendStatus(200).end(); } catch (e) { console.error(e.message, e); response.sendStatus(500).end(); } } );
app.delete( "/workspace/:slug/thread-bulk-delete", [validatedRequest, flexUserRoleValid([ROLES.all]), validWorkspaceSlug], async (request, response) => { try { const { slugs = [] } = reqBody(request); if (slugs.length === 0) return response.sendStatus(200).end();
const user = await userFromSession(request, response); const workspace = response.locals.workspace; await WorkspaceThread.delete({ slug: { in: slugs }, user_id: user?.id ?? null, workspace_id: workspace.id, }); response.sendStatus(200).end(); } catch (e) { console.error(e.message, e); response.sendStatus(500).end(); } } );
app.get( "/workspace/:slug/thread/:threadSlug/chats", [ validatedRequest, flexUserRoleValid([ROLES.all]), validWorkspaceAndThreadSlug, ], async (request, response) => { try { const user = await userFromSession(request, response); const workspace = response.locals.workspace; const thread = response.locals.thread; const history = await WorkspaceChats.where( { workspaceId: workspace.id, user_id: user?.id || null, thread_id: thread.id, api_session_id: null, // Do not include API session chats.
include: true, }, null, { id: "asc" } );
response.status(200).json({ history: convertToChatHistory(history) }); } catch (e) { console.error(e.message, e); response.sendStatus(500).end(); } } );
app.post( "/workspace/:slug/thread/:threadSlug/update", [ validatedRequest, flexUserRoleValid([ROLES.all]), validWorkspaceAndThreadSlug, ], async (request, response) => { try { const data = reqBody(request); const currentThread = response.locals.thread; const { thread, message } = await WorkspaceThread.update( currentThread, data ); response.status(200).json({ thread, message }); } catch (e) { console.error(e.message, e); response.sendStatus(500).end(); } } );
app.delete( "/workspace/:slug/thread/:threadSlug/delete-edited-chats", [ validatedRequest, flexUserRoleValid([ROLES.all]), validWorkspaceAndThreadSlug, ], async (request, response) => { try { const { startingId } = reqBody(request); const user = await userFromSession(request, response); const workspace = response.locals.workspace; const thread = response.locals.thread;
await WorkspaceChats.delete({ workspaceId: Number(workspace.id), thread_id: Number(thread.id), user_id: user?.id, id: { gte: Number(startingId) }, });
response.sendStatus(200).end(); } catch (e) { console.error(e.message, e); response.sendStatus(500).end(); } } );
app.post( "/workspace/:slug/thread/:threadSlug/update-chat", [ validatedRequest, flexUserRoleValid([ROLES.all]), validWorkspaceAndThreadSlug, ], async (request, response) => { try { const { chatId, newText = null } = reqBody(request); if (!newText || !String(newText).trim()) throw new Error("Cannot save empty response");
const user = await userFromSession(request, response); const workspace = response.locals.workspace; const thread = response.locals.thread; const existingChat = await WorkspaceChats.get({ workspaceId: workspace.id, thread_id: thread.id, user_id: user?.id, id: Number(chatId), }); if (!existingChat) throw new Error("Invalid chat.");
const chatResponse = safeJsonParse(existingChat.response, null); if (!chatResponse) throw new Error("Failed to parse chat response");
await WorkspaceChats._update(existingChat.id, { response: JSON.stringify({ ...chatResponse, text: String(newText), }), });
response.sendStatus(200).end(); } catch (e) { console.error(e.message, e); response.sendStatus(500).end(); } } );}
module.exports = { workspaceThreadEndpoints };
|