| 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"); |
| const { getModelTag } = require("./utils"); |
|
|
| 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", |
| LLMModel: getModelTag(), |
| }, |
| 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, |
| 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 }; |
|
|