Skip to content
Open
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
6bb8e6e
feat: Integrate new theme across homepage, navbar, header, and footer
itsnothuy Sep 24, 2025
98ca66c
feat: Finalize dashboard page styling, preserving only Create Room Lo…
itsnothuy Sep 26, 2025
e15be15
feat: Layout and styling improvements for chat and dashboard pages, n…
itsnothuy Sep 27, 2025
1a8c7aa
fix: Manually applied corrections to navbar and chat page layout
itsnothuy Sep 27, 2025
29bf73f
fix: Reverted specific styling in human/create-room page, preserving …
itsnothuy Sep 28, 2025
8c2be5c
Fix chat functionality: AI SDK 4.x migration and Gemini API integration
itsnothuy Sep 29, 2025
fbd299e
feat: Implement Interview Coder theme, fix Tailwind/PostCSS configura…
Sep 30, 2025
2984bdd
fix: resolve dev server runtime errors
Jan 14, 2026
8a1e7a3
feat(design-system): Implement CodePair frontend patterns P0-P2
Jan 14, 2026
b4d9f96
feat(ui): Add IBM Carbon status variants for Badge and Toast components
Jan 14, 2026
ed9ff60
feat(theme): Apply InterviewCoder dark charcoal + gold theme
Jan 14, 2026
dfbaf60
fix(theme): Convert CSS variables to HSL format for Tailwind compatib…
Jan 14, 2026
eb4bf8b
Add comprehensive frontend audit report for InterviewPrep vs CodePair…
Jan 15, 2026
dd5f869
fix(P0): critical UX and security fixes
Jan 15, 2026
7bde354
docs: add P0 implementation summary and detailed breakdown
Jan 15, 2026
2c06f81
feat(P1): improve accessibility and optimize PDF modal
Jan 15, 2026
df77243
docs: rename and append P1 report to implementation summary
Jan 15, 2026
2ba93d6
feat(P1.2): implement pagination system for human rooms
Jan 15, 2026
0dad2b2
feat(P2): implement optional polish and enhancements
Jan 15, 2026
03739e4
feat(human-rooms): Implement all P0 critical fixes
Jan 15, 2026
150f45e
docs: Add P0 testing guide for quick validation
Jan 15, 2026
f8858bb
feat(human-rooms): Implement P1 Prompt1 low-risk improvements
Jan 15, 2026
2aea1eb
docs(human-rooms): Merge P0 and P1 Prompt1 documentation into FIXED_I…
Jan 15, 2026
d225e6f
feat(design-system): Implement P1.1a IBM Carbon design token infrastr…
Jan 15, 2026
8a900ba
feat(design-system): Implement P1.1b - Apply IBM Carbon design tokens…
Jan 15, 2026
aa15238
feat(layout-accessibility): Implement P1.3 (h-screen app shell) and P…
Jan 15, 2026
3203911
chore: Exclude codepair reference codebase from compilation
Jan 15, 2026
344b05c
docs: Add comprehensive architecture gap analysis between codepair an…
Jan 15, 2026
41c2891
refactor(human): Reorganize app/human folder structure and apply UI e…
Jan 16, 2026
8fc3c94
fix(resume-ai): Fix CSS positioning conflict causing content to disap…
Jan 16, 2026
5ac362a
fix(resume-ai): Restore server component architecture with client wra…
Jan 16, 2026
66da6fb
feat(human-rooms): Implement Phase 4 - CodePair architecture improvem…
Jan 16, 2026
59a9f5d
feat(human-rooms): Add layout toggle and fix navbar overlap
Jan 16, 2026
63dfbef
feat: Hide navbar on human-rooms routes and improve responsive home c…
Jan 16, 2026
b834907
feat(code-editor): Major improvements to CodeEditorBlock and home cards
Jan 16, 2026
958a61b
feat(code-editor): Change to top-bottom layout with resizable rows an…
Jan 16, 2026
69c984c
fix(code-editor): Fix resizable top-bottom not working - event listen…
Jan 16, 2026
df1d92e
fix(code-editor): Fix editor overlapping with output panel
Jan 16, 2026
fce8cfb
docs: Add comprehensive postmortem for code editor refactoring
Jan 16, 2026
3660069
fix(code-editor): Fix header buttons wrapping to next line
Jan 17, 2026
202a266
docs(audit): Add comprehensive technical audit for chat page
Jan 17, 2026
fc757f6
security(P0): Fix critical vulnerabilities - IDOR, missing auth, XSS
Jan 17, 2026
8ddef84
security/ux(P1): Implement 7/9 high priority fixes
Jan 17, 2026
bfddc41
feat(P2): Implement 11/12 medium priority fixes
Jan 18, 2026
8a327a1
feat(P3): Implement 7/8 low priority polish fixes
Jan 18, 2026
c11e20d
feat: Complete all deferred P1-P3 audit items
Jan 18, 2026
49009be
docs: Add comprehensive Chat Page Redesign Report (Jan 18, 2026)
Jan 18, 2026
700ccba
fix: Enable independent scrolling for each panel in chat page
Jan 18, 2026
d02bab3
feat: install react-resizable-panels for resizable layout
Jan 18, 2026
f29e16c
feat: create ChatLayout component with resizable panels
Jan 18, 2026
d5871d8
refactor: use ChatLayout in chat page for resizable UI
Jan 18, 2026
75a2d60
docs: add resizable columns implementation documentation
Jan 18, 2026
90ec760
fix: resolve resizable panels CSS conflicts
Jan 18, 2026
892af45
docs: comprehensive debug analysis for resizable panels fix
Jan 18, 2026
9239dce
revert: remove react-resizable-panels library, restore original layout
Jan 18, 2026
922a3af
feat: implement custom resizable sidebar with POSTMORTEM patterns
Jan 18, 2026
e609bff
docs: comprehensive custom resize implementation documentation
Jan 18, 2026
fb827de
fix: correct resize mouse tracking - use delta not absolute position
Jan 18, 2026
6ca2e37
feat: migrate from @google/generative-ai to @google/genai (new SDK)
Jan 18, 2026
488dc47
feat: migrate from Google Gemini to Ollama (Llama 3.1)
itsnothuy Jan 31, 2026
b2709a4
docs: add comprehensive audit of app/ai folder
itsnothuy Jan 31, 2026
ce2945d
feat(security): Complete Phase 1 - All P0 security fixes for app/ai f…
itsnothuy Jan 31, 2026
e8d1361
feat(performance): Complete Phase 2 - All P1 performance & architectu…
itsnothuy Feb 1, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
378 changes: 378 additions & 0 deletions CHAT_API_TROUBLESHOOTING_GUIDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,378 @@
# Chat API Troubleshooting Guide: AI SDK 4.x Migration & Gemini Integration

## Overview
This document chronicles the complete troubleshooting process for migrating from AI SDK 3.x to 4.x and integrating Google Gemini API for chat functionality in a Next.js application. This serves as both a postmortem and a reference guide for similar issues.

## Initial Problem
After 5 months of project inactivity, the chat functionality was completely broken with multiple cascading errors when attempting to send messages.

## Error Timeline & Solutions

### 1. Environment Variable Issues
**Error:** `TypeError: fetch failed` in middleware
**Root Cause:** Missing/expired Upstash Redis credentials
**Solution:** Updated `.env` file with new Upstash Redis credentials
```bash
UPSTASH_REDIS_REST_URL=your_url_here
UPSTASH_REDIS_REST_TOKEN=your_new_token_here
```

### 2. AI SDK Import Errors
**Error:** `Module not found: Package path ./react is not exported from package .../ai`
**Root Cause:** AI SDK 4.x removed the `/react` export path
**Diagnosis:** The `useChat` hook import path changed from `"ai/react"` to `"@ai-sdk/react"`
**Solution:** Updated imports in `components/chat/ChatComponent.tsx`
```javascript
// OLD (AI SDK 3.x)
import { useChat } from "ai/react";

// NEW (AI SDK 4.x)
import { useChat, type UIMessage } from "@ai-sdk/react";
```

### 3. Message Structure Breaking Changes
**Error:** `"Module not found: Package path ./react is not exported"`
**Root Cause:** `UIMessage` structure changed from having `content` property to `parts` array
**Solution:** Updated message rendering in `components/chat/Message.tsx`
```javascript
// OLD
<Markdown text={message.content} />

// NEW
<Markdown text={
message.parts?.find(part => part.type === "text")?.text || ""
} />
```

### 4. Embeddings Context Extraction Error
**Error:** `TypeError: Cannot read properties of undefined (reading 'replace')`
**Root Cause:** Chat API trying to extract `lastMessage.content` which doesn't exist in new `UIMessage` structure
**Solution:** Updated `app/api/chat/route.ts` to extract text from `parts` array
```javascript
// OLD
const context1 = await getContext(lastMessage.content, fileKey);

// NEW
const messageText = lastMessage.parts?.find((part: any) => part.type === "text")?.text || lastMessage.content || "";
const context1 = await getContext(messageText, fileKey);
```

### 5. Message Conversion API Errors
**Error:** `Invalid prompt: The messages must be a ModelMessage[]. If you have passed a UIMessage[], you can use convertToModelMessages`
**Root Cause:** AI SDK 4.x requires explicit conversion from `UIMessage[]` to `ModelMessage[]`
**Initial Solution:** Used `convertToModelMessages` function
```javascript
import { convertToModelMessages } from "ai";
const modelMessages = convertToModelMessages(allMessages);
```

### 6. Filter Method Errors
**Error:** `TypeError: Cannot read properties of undefined (reading 'filter')`
**Root Cause:** `convertToModelMessages` receiving undefined or malformed message arrays
**Solution:** Added validation and fallback conversion
```javascript
// Validate messages array
if (!messages || !Array.isArray(messages)) {
return NextResponse.json({ error: "Invalid messages format" }, { status: 400 });
}

// Fallback conversion if convertToModelMessages fails
try {
modelMessages = convertToModelMessages(allMessages);
} catch (error) {
modelMessages = allMessages.map((msg: any) => ({
role: msg.role,
content: msg.parts?.find((part: any) => part.type === "text")?.text || msg.content || ""
}));
}
```

### 7. API Key Environment Variable Mismatch
**Error:** `LoadAPIKeyError: Google Generative AI API key is missing`
**Root Cause:** Inconsistent environment variable names between old and new code
**Solution:** Standardized to `GOOGLE_GENERATIVE_AI_API_KEY`
```bash
# .env file
GOOGLE_GENERATIVE_AI_API_KEY=your_gemini_api_key_here
```
Updated `utils/embeddings.ts`:
```javascript
const genAI = new GoogleGenerativeAI(process.env.GOOGLE_GENERATIVE_AI_API_KEY as string);
```

### 8. Gemini Model Availability Issues
**Error:** `models/gemini-1.5-flash is not found for API version v1beta`
**Root Cause:** Multiple issues with model names and API versions
**Research:** Found Stack Overflow and GitHub discussions revealing:
- Gemini 1.5+ models require `v1beta` API version
- Model names must match exactly with official documentation

**Evolution of Solutions:**
1. **Wrong model name:** `"gemini-1.5-flash"` → not found
2. **Added version suffix:** `"gemini-1.5-flash-latest"` → still not found
3. **Tried specific version:** `"gemini-1.5-flash-001"` → still not found
4. **Added API version:** `{ apiVersion: 'v1beta' }` → progress but still not found
5. **Switched to Pro model:** `"gemini-1.5-pro"` → still not found
6. **Final solution:** `"gemini-2.0-flash-lite"` with `v1beta` → SUCCESS ✅

### 9. AI SDK Compatibility Issues
**Root Cause:** `@ai-sdk/google` package had persistent API compatibility issues
**Final Solution:** Replaced with direct `@google/generative-ai` SDK
```javascript
// Removed problematic AI SDK imports
// import { google } from "@ai-sdk/google";
// import { streamText, convertToModelMessages } from "ai";

// Added direct Google AI SDK
import { GoogleGenerativeAI } from "@google/generative-ai";
```

### 10. Manual Chat Implementation
**Root Cause:** `useChat` hook from AI SDK 4.x had too many breaking changes
**Solution:** Implemented manual chat functionality
```javascript
// Manual state management
const [messages, setMessages] = useState<UIMessage[]>([]);
const [isGenerating, setIsGenerating] = useState(false);

// Manual API calls with streaming
const response = await fetch("/api/chat", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ messages: newMessages, chatId }),
});

// Manual streaming response handling
const reader = response.body?.getReader();
const decoder = new TextDecoder();
// ... streaming logic
```

## Final Working Configuration

### Environment Variables
```bash
# .env
GOOGLE_GENERATIVE_AI_API_KEY=your_api_key_from_google_ai_studio
UPSTASH_REDIS_REST_URL=your_upstash_url
UPSTASH_REDIS_REST_TOKEN=your_upstash_token
# ... other variables
```

### Chat API Route (`app/api/chat/route.ts`)
```javascript
import { NextResponse } from "next/server";
import { GoogleGenerativeAI } from "@google/generative-ai";
import { eq } from "drizzle-orm";
import { db } from "@/utils/db";
import { chats } from "@/utils/schema";
import { getContext } from "@/app/context";

export async function POST(req: Request) {
try {
const { messages, chatId } = await req.json();

// Validate messages array
if (!messages || !Array.isArray(messages)) {
return NextResponse.json({ error: "Invalid messages format" }, { status: 400 });
}

// Get chat and file key for context
const _chats = await db.select().from(chats).where(eq(chats.id, chatId));
if (_chats.length !== 1) {
return NextResponse.json({ error: "chat not found" }, { status: 404 });
}
const fileKey = _chats[0].fileKey;

// Extract context from last message
const lastMessage = messages[messages.length - 1];
const messageText = lastMessage?.parts?.find((part: any) => part.type === "text")?.text || lastMessage?.content || "";
const context1 = await getContext(messageText, fileKey);

// Build system instruction
const systemContent = `
AI assistant is a brand new, powerful, human-like artificial intelligence.
Traits: expert knowledge, helpfulness, cleverness, articulateness; friendly, kind, inspiring.
Big fan of Pinecone and Vercel.
START CONTEXT BLOCK
${context1}
END OF CONTEXT BLOCK
The assistant will consider any CONTEXT BLOCK provided. It will not apologize for previous responses but will indicate when new information was gained.
`.trim();

// Initialize Google AI with correct model and API version
const genAI = new GoogleGenerativeAI(process.env.GOOGLE_GENERATIVE_AI_API_KEY!);
const model = genAI.getGenerativeModel({ model: "gemini-2.0-flash-lite" }, { apiVersion: 'v1beta' });

// Convert messages and build conversation history
const validMessages = messages.filter((msg: any) => msg && msg.role);

// Add system instruction as conversation starter
const systemHistory = [
{ role: "user", parts: [{ text: systemContent }] },
{ role: "model", parts: [{ text: "I understand. I am an AI assistant with expert knowledge, helpfulness, cleverness, and articulateness. I'm friendly, kind, and inspiring. I'll consider any context provided and indicate when new information is gained without apologizing for previous responses." }] }
];

const messageHistory = validMessages
.filter((msg: any) => msg.role !== "system")
.map((msg: any) => ({
role: msg.role === "user" ? "user" : "model",
parts: [{ text: msg.parts?.find((part: any) => part.type === "text")?.text || msg.content || "" }]
}));

const fullHistory = [...systemHistory, ...messageHistory.slice(0, -1)];

// Start chat and get streaming response
const chat = model.startChat({ history: fullHistory });
const lastUserMessage = validMessages[validMessages.length - 1];
const userInput = lastUserMessage.parts?.find((part: any) => part.type === "text")?.text || lastUserMessage.content || "";
const result = await chat.sendMessageStream(userInput);

// Create streaming response
const stream = new ReadableStream({
async start(controller) {
try {
for await (const chunk of result.stream) {
const chunkText = chunk.text();
controller.enqueue(new TextEncoder().encode(chunkText));
}
controller.close();
} catch (error) {
controller.error(error);
}
}
});

return new Response(stream, {
headers: {
'Content-Type': 'text/plain; charset=utf-8',
'Transfer-Encoding': 'chunked',
},
});
} catch (error) {
console.error("Chat API Error:", error);
return NextResponse.json({ error: "Internal Server Error" }, { status: 500 });
}
}
```

### Client Component (`components/chat/ChatComponent.tsx`)
```javascript
// Manual implementation replacing useChat hook
const [messages, setMessages] = useState<UIMessage[]>([]);
const [isGenerating, setIsGenerating] = useState(false);

const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
if (!input.trim() || isGenerating) return;

const userMessage: UIMessage = {
id: Date.now().toString(),
role: "user",
parts: [{ type: "text", text: input }],
};

const newMessages = [...messages, userMessage];
setMessages(newMessages);
setInput("");
setIsGenerating(true);

try {
const response = await fetch("/api/chat", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ messages: newMessages, chatId }),
});

// Handle streaming response...
} catch (error) {
console.error("Error sending message:", error);
} finally {
setIsGenerating(false);
}
};
```

## Key Lessons Learned

### 1. **Breaking Changes in Major Versions**
- AI SDK 4.x introduced significant breaking changes
- Import paths, hook APIs, and message structures all changed
- Always check migration guides for major version updates

### 2. **Model Name Precision**
- Model names must match exactly with official documentation
- Different API versions support different models
- Use official model pages (like Gemini Models page) as source of truth

### 3. **API Version Importance**
- Beta features require explicit API version specification
- `v1beta` vs `v1` can determine model availability
- Always specify API version for consistency

### 4. **Environment Variable Consistency**
- Different packages may expect different environment variable names
- Standardize on one naming convention across the application
- Document expected environment variables clearly

### 5. **Fallback Strategies**
- When third-party hooks break, manual implementation may be more reliable
- Direct SDK usage often provides more control than wrapper libraries
- Keep fallback options for critical functionality

### 6. **Debugging Approach**
- Start with the most specific error message
- Work backwards through the call stack
- Use official documentation and community discussions (Stack Overflow, GitHub)
- Test each change incrementally

## Verification Steps

To verify the chat is working correctly:

1. **Environment Setup:**
```bash
# Check .env file has correct variables
cat .env | grep GOOGLE_GENERATIVE_AI_API_KEY
```

2. **Start Development Server:**
```bash
npm run dev
```

3. **Test Chat Functionality:**
- Navigate to `/chat/[chatId]`
- Send a test message like "hello"
- Verify streaming response appears
- Check browser console for errors
- Check server logs for API calls

4. **Expected Behavior:**
- Message appears immediately in chat
- AI response streams in real-time
- No console errors
- Proper message formatting with Markdown support

## Future Considerations

1. **Model Updates:** Gemini model names may change; monitor official documentation
2. **API Version Migration:** Eventually migrate from `v1beta` to stable `v1` when available
3. **Error Handling:** Add more robust error handling and user feedback
4. **Performance:** Consider implementing message caching and optimistic updates
5. **Monitoring:** Add logging and monitoring for chat API usage and errors

## Resources Used

- [AI SDK 4.x Documentation](https://sdk.vercel.ai/)
- [Google AI Studio](https://aistudio.google.com/)
- [Gemini Models Official Page](https://ai.google.dev/gemini-api/docs/models/gemini)
- [Stack Overflow: Model not found when using gemini 1.5](https://stackoverflow.com/questions/...)
- [GitHub Discussion: Dify Gemini Integration](https://github.com/langgenius/dify/discussions/17263)

---

**Created:** January 2025
**Last Updated:** January 2025
**Status:** ✅ Resolved - Chat functionality fully operational

Loading
Loading