From 71b57b314b6f0d0b8e71986c7642b8e44b2b8748 Mon Sep 17 00:00:00 2001 From: Urjit Chakraborty <135136842+urjitc@users.noreply.github.com> Date: Tue, 21 Apr 2026 11:23:33 -0400 Subject: [PATCH 01/19] chore: remove @assistant-ui dependency and legacy runtime Clears the way for the new ChatProvider/useChat-based architecture by deleting every @assistant-ui consumer and its scaffolding: - Delete src/components/assistant-ui/** (thread, tool UIs, runtime provider, toolkit, dropzone, speech-to-text, mention menu, etc.). - Delete AUI-coupled chat shells: AppChatHeader, MentionMenu, and MessageContextBadges. - Delete the runtime/adapter glue: AssistantAvailabilityContext, src/lib/chat/runtime/**, custom-thread-history-adapter, custom-thread-list-adapter, toCreateMessageWithContext, and the supabase-attachment-adapter. - Drop the /api/threads/[id]/messages/[messageId] branch-switch endpoint (edit/regenerate is now handled server-side in /api/chat) and the /api/threads/[id]/title endpoint (titles now stream inline via data-chat-title on the main SSE stream). - package.json: remove @assistant-ui/*, assistant-stream, and the speech-recognition deps these components pulled in. No runtime changes land in this commit; follow-ups introduce the replacements. Made-with: Cursor --- package.json | 7 - .../[id]/messages/[messageId]/route.ts | 78 -- src/app/api/threads/[id]/title/route.ts | 132 --- .../assistant-ui/AIFeedbackDialog.tsx | 86 -- .../assistant-ui/AddYoutubeVideoToolUI.tsx | 155 ---- .../assistant-ui/AssistantDropzone.tsx | 215 ----- .../assistant-ui/AssistantPanel.tsx | 149 ---- .../AssistantTextSelectionManager.tsx | 114 --- .../assistant-ui/CreateDocumentToolUI.tsx | 262 ------ .../assistant-ui/CreateFlashcardToolUI.tsx | 324 -------- .../assistant-ui/CreateQuizToolUI.tsx | 284 ------- .../assistant-ui/EditItemToolUI.tsx | 203 ----- .../assistant-ui/ExecuteCodeToolUI.tsx | 135 --- src/components/assistant-ui/ModelPicker.tsx | 260 ------ .../assistant-ui/ModelSettingsMenu.tsx | 81 -- .../assistant-ui/PromptBuilderDialog.tsx | 774 ------------------ .../assistant-ui/ReadWorkspaceToolUI.tsx | 92 --- .../assistant-ui/SearchWorkspaceToolUI.tsx | 55 -- .../assistant-ui/SpeechToTextButton.tsx | 73 -- .../assistant-ui/URLContextToolUI.tsx | 337 -------- .../assistant-ui/WebSearchToolUI.tsx | 303 ------- .../assistant-ui/WorkspaceRuntimeProvider.tsx | 259 ------ .../assistant-ui/YouTubeSearchToolUI.tsx | 392 --------- .../assistant-ui/assistant-loader.tsx | 29 - .../assistant-thread-selection.tsx | 228 ------ src/components/assistant-ui/attachment.tsx | 467 ----------- src/components/assistant-ui/chat-toolkit.tsx | 94 --- src/components/assistant-ui/diff-viewer.tsx | 625 -------------- src/components/assistant-ui/file.tsx | 235 ------ src/components/assistant-ui/image.tsx | 264 ------ src/components/assistant-ui/markdown-text.tsx | 303 ------- src/components/assistant-ui/reasoning.tsx | 310 ------- src/components/assistant-ui/sources.tsx | 148 ---- .../assistant-ui/standalone-markdown.tsx | 289 ------- .../assistant-ui/thread-list-dropdown.tsx | 325 -------- src/components/assistant-ui/thread.tsx | 1 - .../thread/AssistantActionBar.tsx | 45 - .../assistant-ui/thread/AssistantMessage.tsx | 50 -- .../assistant-ui/thread/BranchPicker.tsx | 41 - .../assistant-ui/thread/EditPromptInput.tsx | 81 -- .../assistant-ui/thread/MessageError.tsx | 14 - .../assistant-ui/thread/PromptInput.tsx | 159 ---- .../assistant-ui/thread/PromptInputShell.tsx | 167 ---- .../thread/PromptInputToolbar.tsx | 187 ----- src/components/assistant-ui/thread/Thread.tsx | 46 -- .../thread/ThreadLoadingSkeleton.tsx | 34 - .../assistant-ui/thread/ThreadSuggestions.tsx | 92 --- .../assistant-ui/thread/ThreadWelcome.tsx | 27 - .../assistant-ui/thread/UserActionBar.tsx | 46 -- .../assistant-ui/thread/UserMessage.tsx | 92 --- .../thread/UserMessageTruncateContext.tsx | 30 - .../thread/VirtualizedMessages.tsx | 55 -- .../thread/hooks/use-mention-menu.ts | 153 ---- .../thread/hooks/use-prompt-input-paste.ts | 56 -- src/components/assistant-ui/thread/index.ts | 1 - .../assistant-ui/thread/message-components.ts | 9 - .../thread/prompt-input-floating-actions.ts | 53 -- .../assistant-ui/thread/suggestion-actions.ts | 47 -- src/components/assistant-ui/tool-fallback.tsx | 46 -- src/components/assistant-ui/tool-group.tsx | 250 ------ .../assistant-ui/tool-ui-error-shell.tsx | 51 -- .../assistant-ui/tool-ui-loading-shell.tsx | 43 - .../assistant-ui/tooltip-icon-button.tsx | 59 -- src/components/chat/AppChatHeader.tsx | 447 ---------- src/components/chat/MentionMenu.tsx | 154 ---- src/components/chat/MessageContextBadges.tsx | 53 -- src/contexts/AssistantAvailabilityContext.tsx | 49 -- .../supabase-attachment-adapter.ts | 110 --- .../custom-thread-history-adapter.test.ts | 281 ------- .../chat/custom-thread-history-adapter.tsx | 229 ------ src/lib/chat/custom-thread-list-adapter.tsx | 137 ---- src/lib/chat/runtime/hooks.ts | 308 ------- src/lib/chat/runtime/index.ts | 19 - src/lib/chat/runtime/primitives.ts | 26 - src/lib/chat/runtime/types.ts | 118 --- src/lib/chat/toCreateMessageWithContext.ts | 62 -- 76 files changed, 12015 deletions(-) delete mode 100644 src/app/api/threads/[id]/messages/[messageId]/route.ts delete mode 100644 src/app/api/threads/[id]/title/route.ts delete mode 100644 src/components/assistant-ui/AIFeedbackDialog.tsx delete mode 100644 src/components/assistant-ui/AddYoutubeVideoToolUI.tsx delete mode 100644 src/components/assistant-ui/AssistantDropzone.tsx delete mode 100644 src/components/assistant-ui/AssistantPanel.tsx delete mode 100644 src/components/assistant-ui/AssistantTextSelectionManager.tsx delete mode 100644 src/components/assistant-ui/CreateDocumentToolUI.tsx delete mode 100644 src/components/assistant-ui/CreateFlashcardToolUI.tsx delete mode 100644 src/components/assistant-ui/CreateQuizToolUI.tsx delete mode 100644 src/components/assistant-ui/EditItemToolUI.tsx delete mode 100644 src/components/assistant-ui/ExecuteCodeToolUI.tsx delete mode 100644 src/components/assistant-ui/ModelPicker.tsx delete mode 100644 src/components/assistant-ui/ModelSettingsMenu.tsx delete mode 100644 src/components/assistant-ui/PromptBuilderDialog.tsx delete mode 100644 src/components/assistant-ui/ReadWorkspaceToolUI.tsx delete mode 100644 src/components/assistant-ui/SearchWorkspaceToolUI.tsx delete mode 100644 src/components/assistant-ui/SpeechToTextButton.tsx delete mode 100644 src/components/assistant-ui/URLContextToolUI.tsx delete mode 100644 src/components/assistant-ui/WebSearchToolUI.tsx delete mode 100644 src/components/assistant-ui/WorkspaceRuntimeProvider.tsx delete mode 100644 src/components/assistant-ui/YouTubeSearchToolUI.tsx delete mode 100644 src/components/assistant-ui/assistant-loader.tsx delete mode 100644 src/components/assistant-ui/assistant-thread-selection.tsx delete mode 100644 src/components/assistant-ui/attachment.tsx delete mode 100644 src/components/assistant-ui/chat-toolkit.tsx delete mode 100644 src/components/assistant-ui/diff-viewer.tsx delete mode 100644 src/components/assistant-ui/file.tsx delete mode 100644 src/components/assistant-ui/image.tsx delete mode 100644 src/components/assistant-ui/markdown-text.tsx delete mode 100644 src/components/assistant-ui/reasoning.tsx delete mode 100644 src/components/assistant-ui/sources.tsx delete mode 100644 src/components/assistant-ui/standalone-markdown.tsx delete mode 100644 src/components/assistant-ui/thread-list-dropdown.tsx delete mode 100644 src/components/assistant-ui/thread.tsx delete mode 100644 src/components/assistant-ui/thread/AssistantActionBar.tsx delete mode 100644 src/components/assistant-ui/thread/AssistantMessage.tsx delete mode 100644 src/components/assistant-ui/thread/BranchPicker.tsx delete mode 100644 src/components/assistant-ui/thread/EditPromptInput.tsx delete mode 100644 src/components/assistant-ui/thread/MessageError.tsx delete mode 100644 src/components/assistant-ui/thread/PromptInput.tsx delete mode 100644 src/components/assistant-ui/thread/PromptInputShell.tsx delete mode 100644 src/components/assistant-ui/thread/PromptInputToolbar.tsx delete mode 100644 src/components/assistant-ui/thread/Thread.tsx delete mode 100644 src/components/assistant-ui/thread/ThreadLoadingSkeleton.tsx delete mode 100644 src/components/assistant-ui/thread/ThreadSuggestions.tsx delete mode 100644 src/components/assistant-ui/thread/ThreadWelcome.tsx delete mode 100644 src/components/assistant-ui/thread/UserActionBar.tsx delete mode 100644 src/components/assistant-ui/thread/UserMessage.tsx delete mode 100644 src/components/assistant-ui/thread/UserMessageTruncateContext.tsx delete mode 100644 src/components/assistant-ui/thread/VirtualizedMessages.tsx delete mode 100644 src/components/assistant-ui/thread/hooks/use-mention-menu.ts delete mode 100644 src/components/assistant-ui/thread/hooks/use-prompt-input-paste.ts delete mode 100644 src/components/assistant-ui/thread/index.ts delete mode 100644 src/components/assistant-ui/thread/message-components.ts delete mode 100644 src/components/assistant-ui/thread/prompt-input-floating-actions.ts delete mode 100644 src/components/assistant-ui/thread/suggestion-actions.ts delete mode 100644 src/components/assistant-ui/tool-fallback.tsx delete mode 100644 src/components/assistant-ui/tool-group.tsx delete mode 100644 src/components/assistant-ui/tool-ui-error-shell.tsx delete mode 100644 src/components/assistant-ui/tool-ui-loading-shell.tsx delete mode 100644 src/components/assistant-ui/tooltip-icon-button.tsx delete mode 100644 src/components/chat/AppChatHeader.tsx delete mode 100644 src/components/chat/MentionMenu.tsx delete mode 100644 src/components/chat/MessageContextBadges.tsx delete mode 100644 src/contexts/AssistantAvailabilityContext.tsx delete mode 100644 src/lib/attachments/supabase-attachment-adapter.ts delete mode 100644 src/lib/chat/custom-thread-history-adapter.test.ts delete mode 100644 src/lib/chat/custom-thread-history-adapter.tsx delete mode 100644 src/lib/chat/custom-thread-list-adapter.tsx delete mode 100644 src/lib/chat/runtime/hooks.ts delete mode 100644 src/lib/chat/runtime/index.ts delete mode 100644 src/lib/chat/runtime/primitives.ts delete mode 100644 src/lib/chat/runtime/types.ts delete mode 100644 src/lib/chat/toCreateMessageWithContext.ts diff --git a/package.json b/package.json index 92ea88fa..f2965001 100644 --- a/package.json +++ b/package.json @@ -32,10 +32,6 @@ "dependencies": { "@ai-sdk/devtools": "^0.0.15", "@ai-sdk/google": "^3.0.62", - "@assistant-ui/react": "^0.12.24", - "@assistant-ui/react-ai-sdk": "^1.3.18", - "@assistant-ui/react-devtools": "^1.0.5", - "@assistant-ui/react-markdown": "^0.12.8", "@contextcompany/otel": "^1.0.15", "@e2b/code-interpreter": "^2.4.0", "@embedpdf/core": "^2.14.0", @@ -116,7 +112,6 @@ "@workflow/errors": "4.1.0", "ai": "^6.0.158", "assemblyai": "^4.29.0", - "assistant-stream": "^0.3.10", "better-auth": "^1.6.2", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", @@ -150,7 +145,6 @@ "react-quizlet-flashcard": "^4.0.22", "react-resizable-panels": "^4.9.0", "react-shiki": "^0.9.1", - "react-speech-recognition": "^4.0.1", "regenerator-runtime": "^0.14.1", "rehype-katex": "^7.0.1", "remark-gfm": "^4.0.1", @@ -176,7 +170,6 @@ "@types/react": "19.2.14", "@types/react-color": "^3.0.13", "@types/react-dom": "19.2.3", - "@types/react-speech-recognition": "^3.9.6", "@typescript/native-preview": "7.0.0-dev.20260408.1", "babel-plugin-react-compiler": "^1.0.0", "concurrently": "^9.2.1", diff --git a/src/app/api/threads/[id]/messages/[messageId]/route.ts b/src/app/api/threads/[id]/messages/[messageId]/route.ts deleted file mode 100644 index ef810028..00000000 --- a/src/app/api/threads/[id]/messages/[messageId]/route.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { NextRequest, NextResponse } from "next/server"; -import { db } from "@/lib/db/client"; -import { chatThreads, chatMessages } from "@/lib/db/schema"; -import { - requireAuth, - verifyWorkspaceAccess, - verifyThreadOwnership, -} from "@/lib/api/workspace-helpers"; -import { eq, and } from "drizzle-orm"; -import { withServerObservability } from "@/lib/with-server-observability"; - -async function getThreadAndVerify(threadId: string, userId: string) { - const [thread] = await db - .select() - .from(chatThreads) - .where(eq(chatThreads.id, threadId)) - .limit(1); - - if (!thread) { - throw NextResponse.json({ error: "Thread not found" }, { status: 404 }); - } - - await verifyWorkspaceAccess(thread.workspaceId, userId); - verifyThreadOwnership(thread, userId); - - return thread; -} - -/** - * PATCH /api/threads/[id]/messages/[messageId] - * Update an existing message (e.g. step timestamps/duration from useExternalHistory) - */ -export const PATCH = withServerObservability(async function PATCH( - req: NextRequest, - { params }: { params: Promise<{ id: string; messageId: string }> } -) { - try { - const userId = await requireAuth(); - const { id: threadId, messageId } = await params; - const body = await req.json().catch(() => ({})); - const { content } = body; - - if (content === undefined) { - return NextResponse.json( - { error: "content is required" }, - { status: 400 } - ); - } - - await getThreadAndVerify(threadId, userId); - - const [updated] = await db - .update(chatMessages) - .set({ - content: typeof content === "object" ? content : { raw: content }, - }) - .where( - and( - eq(chatMessages.threadId, threadId), - eq(chatMessages.messageId, messageId) - ) - ) - .returning({ messageId: chatMessages.messageId }); - - if (!updated) { - return NextResponse.json({ error: "Message not found" }, { status: 404 }); - } - - return NextResponse.json({ ok: true }); - } catch (error) { - if (error instanceof Response) return error; - console.error("[threads] messages PATCH error:", error); - return NextResponse.json( - { error: "Internal server error" }, - { status: 500 } - ); - } -}, { routeName: "PATCH /api/threads/[id]/messages/[messageId]" }); diff --git a/src/app/api/threads/[id]/title/route.ts b/src/app/api/threads/[id]/title/route.ts deleted file mode 100644 index 96db1999..00000000 --- a/src/app/api/threads/[id]/title/route.ts +++ /dev/null @@ -1,132 +0,0 @@ -import { NextRequest, NextResponse } from "next/server"; -import { generateText } from "ai"; -import { db } from "@/lib/db/client"; -import { chatThreads } from "@/lib/db/schema"; -import { - requireAuth, - verifyWorkspaceAccess, - verifyThreadOwnership, -} from "@/lib/api/workspace-helpers"; -import { eq } from "drizzle-orm"; -import { withServerObservability } from "@/lib/with-server-observability"; -import { getGatewayModelIdForPurpose } from "@/lib/ai/models"; -import { - buildGatewayProviderOptions, - createGatewayLanguageModel, - getGatewayAttributionHeaders, -} from "@/lib/ai/gateway-provider-options"; - -function extractTextFromMessage(msg: { content?: unknown[] }): string { - if (!msg.content || !Array.isArray(msg.content)) return ""; - return (msg.content as { type?: string; text?: string }[]) - .filter((c) => c.type === "text") - .map((c) => c.text ?? "") - .join(" ") - .trim(); -} - -/** - * POST /api/threads/[id]/title - * Generate a title from messages using Gemini Flash Lite. - * Body: { messages: ThreadMessage[] } - */ -export const POST = withServerObservability( - async function POST( - req: NextRequest, - { params }: { params: Promise<{ id: string }> }, - ) { - try { - const userId = await requireAuth(); - const { id } = await params; - const body = await req.json().catch(() => ({})); - const { messages } = body; - - const [thread] = await db - .select() - .from(chatThreads) - .where(eq(chatThreads.id, id)) - .limit(1); - - if (!thread) { - return NextResponse.json( - { error: "Thread not found" }, - { status: 404 }, - ); - } - - await verifyWorkspaceAccess(thread.workspaceId, userId); - verifyThreadOwnership(thread, userId); - - let title = "New Chat"; - - if (messages && Array.isArray(messages) && messages.length > 0) { - const conversationText = messages - .slice(0, 6) - .map((m: { role?: string; content?: unknown[] }) => { - const text = extractTextFromMessage(m); - if (!text) return ""; - const role = m.role === "user" ? "User" : "Assistant"; - return `${role}: ${text}`; - }) - .filter(Boolean) - .join("\n\n"); - - if (conversationText.trim()) { - try { - const gatewayModelId = - getGatewayModelIdForPurpose("title-generation"); - const { text, providerMetadata } = await generateText({ - model: createGatewayLanguageModel(gatewayModelId), - providerOptions: buildGatewayProviderOptions(gatewayModelId, { - userId, - }) as any, - headers: getGatewayAttributionHeaders(), - system: `Generate a very short chat title (2-6 words) that captures the topic. Output ONLY the title, no quotes or punctuation.`, - prompt: `Conversation:\n\n${conversationText}\n\nTitle:`, - experimental_telemetry: { - isEnabled: true, - metadata: { - "tcc.sessionId": id, - ...(userId ? { userId } : {}), - }, - }, - }); - const provider = - (providerMetadata as any)?.gateway?.routing?.resolvedProvider ?? - (providerMetadata as any)?.gateway?.routing?.finalProvider; - if (provider) { - console.log( - "[threads/title] Gateway resolved provider:", - provider, - ); - } - const generated = text.trim().slice(0, 60); - if (generated) title = generated; - } catch (err) { - console.warn("[threads] title Gemini fallback:", err); - const firstUser = messages.find( - (m: { role?: string }) => m.role === "user", - ); - const fallback = extractTextFromMessage(firstUser ?? {}); - if (fallback) { - title = - fallback.slice(0, 50) + (fallback.length > 50 ? "..." : ""); - } - } - } - } - - await db.update(chatThreads).set({ title }).where(eq(chatThreads.id, id)); - - return NextResponse.json({ title }); - } catch (error) { - if (error instanceof Response) return error; - console.error("[threads] title error:", error); - return NextResponse.json( - { error: "Internal server error" }, - { status: 500 }, - ); - } - }, - { routeName: "POST /api/threads/[id]/title" }, -); diff --git a/src/components/assistant-ui/AIFeedbackDialog.tsx b/src/components/assistant-ui/AIFeedbackDialog.tsx deleted file mode 100644 index 2d501151..00000000 --- a/src/components/assistant-ui/AIFeedbackDialog.tsx +++ /dev/null @@ -1,86 +0,0 @@ -"use client"; - -import { useState, useCallback } from "react"; -import { - Dialog, - DialogContent, - DialogDescription, - DialogFooter, - DialogHeader, - DialogTitle, -} from "@/components/ui/dialog"; -import { Button } from "@/components/ui/button"; -import { Textarea } from "@/components/ui/textarea"; -import { posthog } from "@/lib/posthog-client"; -import { toast } from "sonner"; - -interface AIFeedbackDialogProps { - open: boolean; - onOpenChange: (open: boolean) => void; -} - -export function AIFeedbackDialog({ open, onOpenChange }: AIFeedbackDialogProps) { - const [feedback, setFeedback] = useState(""); - const [isSubmitting, setIsSubmitting] = useState(false); - - const handleSubmit = useCallback(() => { - setIsSubmitting(true); - - const trimmedFeedback = feedback.trim(); - - posthog.capture("ai_debug_feedback_submitted", { - feedback_text: trimmedFeedback, - }); - - toast.success("Feedback submittedβ€”thank you!"); - setFeedback(""); - onOpenChange(false); - setIsSubmitting(false); - }, [feedback, onOpenChange]); - - const handleOpenChange = useCallback( - (nextOpen: boolean) => { - if (!nextOpen && !isSubmitting) { - setFeedback(""); - } - onOpenChange(nextOpen); - }, - [onOpenChange, isSubmitting] - ); - - return ( - - - - Report AI Issue - - What went wrong with the AI? Your feedback helps us improve. - - - -
-