From 95bcae6e3d80285fecf292621b295e5c26d00a60 Mon Sep 17 00:00:00 2001 From: Albert Date: Sun, 9 Nov 2025 04:07:17 +0000 Subject: [PATCH] fix: Migrate chat to AI SDK 5.0 and fix form submission MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Critical fixes to get chat functionality working: 1. **Migrate to AI SDK 5.0 API**: - Replace deprecated `handleSubmit`, `input`, `handleInputChange` from useChat - Use manual state management with `useState` for input - Use `sendMessage({ text })` instead of form submission - Update API route to use `toUIMessageStreamResponse()` instead of `toAIStreamResponse()` - Add `convertToModelMessages()` for proper message conversion - Update message rendering to use `parts` array instead of `content` string 2. **Fix Mantine hydration error**: - Change `forceColorScheme="dark"` to `defaultColorScheme="dark"` in layout - Add `suppressHydrationWarning` to html and body tags - This was preventing React from attaching event handlers to the form 3. **Preserve existing features**: - Keep input padding fix - Keep microphone recorder integration - Keep persona parameter in API route The form now successfully submits and makes POST requests to /api/chat. Next steps: add initial greeting, re-add tool call handling for node suggestions. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- app/api/chat/route.ts | 14 ++++----- app/chat/page.tsx | 68 +++++++++++++++++++------------------------ app/layout.tsx | 8 ++--- 3 files changed, 41 insertions(+), 49 deletions(-) diff --git a/app/api/chat/route.ts b/app/api/chat/route.ts index 1866dcf..0de4e36 100644 --- a/app/api/chat/route.ts +++ b/app/api/chat/route.ts @@ -1,4 +1,4 @@ -import { streamText } from '@ai-sdk/react'; +import { streamText, UIMessage, convertToModelMessages } from 'ai'; import { google } from '@ai-sdk/google'; import { cookies } from 'next/headers'; import { NodeSuggestionSchema } from '@/lib/ai-schemas'; @@ -15,14 +15,14 @@ export async function POST(req: Request) { return new Response('Unauthorized', { status: 401 }); } - const { messages, data } = await req.json(); + const { messages, data }: { messages: UIMessage[]; data?: { persona?: string } } = await req.json(); // Get the 'persona' from the custom 'data' object const { persona } = z .object({ persona: z.string().optional().default('Socratic'), }) - .parse(data); + .parse(data || {}); // Dynamically create the system prompt based on persona const systemPrompt = `You are a ${persona} thought partner. @@ -33,10 +33,10 @@ idea is fully formed. For all other conversation, just respond as a helpful AI.`; // Use the Vercel AI SDK's streamText function with tools - const result = await streamText({ + const result = streamText({ model: google('gemini-1.5-flash'), system: systemPrompt, - messages: messages, + messages: convertToModelMessages(messages), // Provide the schema as a 'tool' to the model tools: { @@ -47,6 +47,6 @@ For all other conversation, just respond as a helpful AI.`; }, }); - // Return the streaming response - return result.toAIStreamResponse(); + // Return the streaming response (v5 API) + return result.toUIMessageStreamResponse(); } diff --git a/app/chat/page.tsx b/app/chat/page.tsx index ae2d316..56f09cf 100644 --- a/app/chat/page.tsx +++ b/app/chat/page.tsx @@ -13,44 +13,18 @@ import { Text, } from '@mantine/core'; import { useRouter } from 'next/navigation'; -import { useEffect, useRef } from 'react'; -import { NodeSuggestion } from '@/lib/ai-schemas'; +import { useEffect, useRef, useState } from 'react'; import { MicrophoneRecorder } from '@/components/MicrophoneRecorder'; export default function ChatPage() { const router = useRouter(); const viewport = useRef(null); + const [input, setInput] = useState(''); - const { - messages, - input, - handleInputChange, - handleSubmit, - setInput, - isLoading, - } = useChat({ + const { messages, sendMessage, isLoading } = useChat({ api: '/api/chat', - // Send the persona in the 'data' property - data: { - persona: 'Socratic', // This could be a