From b30dc1c9560f27764131dacd1e2f24714412a066 Mon Sep 17 00:00:00 2001 From: Timothy Carambat Date: Fri, 7 Jun 2024 17:12:54 -0700 Subject: [PATCH] patch: Auto thread renaming (#1636) --- .../ActiveWorkspaces/ThreadContainer/index.jsx | 5 +++-- .../WorkspaceChat/ChatContainer/index.jsx | 14 -------------- frontend/src/utils/chat/index.js | 16 ++++++++++++++++ server/endpoints/chat.js | 10 ++++++++++ server/models/workspaceThread.js | 14 +++++++++++--- 5 files changed, 40 insertions(+), 19 deletions(-) diff --git a/frontend/src/components/Sidebar/ActiveWorkspaces/ThreadContainer/index.jsx b/frontend/src/components/Sidebar/ActiveWorkspaces/ThreadContainer/index.jsx index f2d99cd8..63cbef7b 100644 --- a/frontend/src/components/Sidebar/ActiveWorkspaces/ThreadContainer/index.jsx +++ b/frontend/src/components/Sidebar/ActiveWorkspaces/ThreadContainer/index.jsx @@ -5,6 +5,7 @@ import { Plus, CircleNotch, Trash } from "@phosphor-icons/react"; import { useEffect, useState } from "react"; import ThreadItem from "./ThreadItem"; import { useParams } from "react-router-dom"; +export const THREAD_RENAME_EVENT = "renameThread"; export default function ThreadContainer({ workspace }) { const { threadSlug = null } = useParams(); @@ -25,10 +26,10 @@ export default function ThreadContainer({ workspace }) { ); }; - window.addEventListener("renameThread", chatHandler); + window.addEventListener(THREAD_RENAME_EVENT, chatHandler); return () => { - window.removeEventListener("renameThread", chatHandler); + window.removeEventListener(THREAD_RENAME_EVENT, chatHandler); }; }, []); diff --git a/frontend/src/components/WorkspaceChat/ChatContainer/index.jsx b/frontend/src/components/WorkspaceChat/ChatContainer/index.jsx index 6e32d23f..cce249ec 100644 --- a/frontend/src/components/WorkspaceChat/ChatContainer/index.jsx +++ b/frontend/src/components/WorkspaceChat/ChatContainer/index.jsx @@ -12,7 +12,6 @@ import handleSocketResponse, { AGENT_SESSION_END, AGENT_SESSION_START, } from "@/utils/chat/agent"; -import truncate from "truncate"; export default function ChatContainer({ workspace, knownHistory = [] }) { const { threadSlug = null } = useParams(); @@ -39,19 +38,6 @@ export default function ChatContainer({ workspace, knownHistory = [] }) { const handleSubmit = async (event) => { event.preventDefault(); if (!message || message === "") return false; - - // If first message and it is a thread - // and message is not blank/whitespace, - // then send event to rename the thread - if (threadSlug && chatHistory.length === 0 && message.trim().length > 0) { - const truncatedName = truncate(message, 22); - window.dispatchEvent( - new CustomEvent("renameThread", { - detail: { threadSlug, newName: truncatedName }, - }) - ); - } - const prevChatHistory = [ ...chatHistory, { content: message, role: "user" }, diff --git a/frontend/src/utils/chat/index.js b/frontend/src/utils/chat/index.js index a57b11e2..58f6d42c 100644 --- a/frontend/src/utils/chat/index.js +++ b/frontend/src/utils/chat/index.js @@ -1,3 +1,4 @@ +import { THREAD_RENAME_EVENT } from "@/components/Sidebar/ActiveWorkspaces/ThreadContainer"; export const ABORT_STREAM_EVENT = "abort-chat-stream"; // For handling of chat responses in the frontend by their various types. @@ -136,6 +137,21 @@ export default function handleChat( // Chat was reset, keep reset message and clear everything else. setChatHistory([_chatHistory.pop()]); } + + // If thread was updated automatically based on chat prompt + // then we can handle the updating of the thread here. + if (action === "rename_thread") { + if (!!chatResult?.thread?.slug && chatResult.thread.name) { + window.dispatchEvent( + new CustomEvent(THREAD_RENAME_EVENT, { + detail: { + threadSlug: chatResult.thread.slug, + newName: chatResult.thread.name, + }, + }) + ); + } + } } export function chatPrompt(workspace) { diff --git a/server/endpoints/chat.js b/server/endpoints/chat.js index 915acbf9..c7e70265 100644 --- a/server/endpoints/chat.js +++ b/server/endpoints/chat.js @@ -199,11 +199,21 @@ function chatEndpoints(app) { thread ); + // If thread was renamed emit event to frontend via special `action` response. await WorkspaceThread.autoRenameThread({ thread, workspace, user, newName: truncate(message, 22), + onRename: (thread) => { + writeResponseChunk(response, { + action: "rename_thread", + thread: { + slug: thread.slug, + name: thread.name, + }, + }); + }, }); await Telemetry.sendTelemetry("sent_chat", { diff --git a/server/models/workspaceThread.js b/server/models/workspaceThread.js index ffbc8aed..32e9f89b 100644 --- a/server/models/workspaceThread.js +++ b/server/models/workspaceThread.js @@ -2,13 +2,14 @@ const prisma = require("../utils/prisma"); const { v4: uuidv4 } = require("uuid"); const WorkspaceThread = { + defaultName: "Thread", writable: ["name"], new: async function (workspace, userId = null) { try { const thread = await prisma.workspace_threads.create({ data: { - name: "Thread", + name: this.defaultName, slug: uuidv4(), user_id: userId ? Number(userId) : null, workspace_id: workspace.id, @@ -91,16 +92,23 @@ const WorkspaceThread = { thread = null, user = null, newName = null, + onRename = null, }) { if (!workspace || !thread || !newName) return false; + if (thread.name !== this.defaultName) return false; // don't rename if already named. + const { WorkspaceChats } = require("./workspaceChats"); const chatCount = await WorkspaceChats.count({ workspaceId: workspace.id, user_id: user?.id || null, thread_id: thread.id, }); - if (chatCount !== 1) return false; - await this.update(thread, { name: newName }); + if (chatCount !== 1) return { renamed: false, thread }; + const { thread: updatedThread } = await this.update(thread, { + name: newName, + }); + + onRename?.(updatedThread); return true; }, };