From c123b11bd8aa13abfb2e51927ababb381dfc8fc0 Mon Sep 17 00:00:00 2001 From: Madison Date: Fri, 22 Aug 2025 11:46:37 -0500 Subject: [PATCH 01/10] new packages, updated packages --- docs/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/package.json b/docs/package.json index ee68c2dbd7..1e3e237403 100644 --- a/docs/package.json +++ b/docs/package.json @@ -22,7 +22,7 @@ "@ai-sdk/google": "^1.2.21", "@ai-sdk/openai": "^1.3.22", "@ai-sdk/react": "^1.2.12", - "@modelcontextprotocol/sdk": "^1.12.0", + "@modelcontextprotocol/sdk": "^1.17.2", "@radix-ui/react-collapsible": "^1.1.11", "@radix-ui/react-popover": "^1.1.14", "@radix-ui/react-presence": "^1.1.4", @@ -33,7 +33,7 @@ "@stackframe/stack-shared": "workspace:^", "@vercel/mcp-adapter": "^1.0.0", "@xyflow/react": "^12.6.4", - "ai": "^4.3.16", + "ai": "^4.3.17", "class-variance-authority": "^0.7.1", "fumadocs-core": "15.3.3", "fumadocs-mdx": "11.6.4", From b504b91209401fb17ab2ee2ceaac4dc9f0ba4c4f Mon Sep 17 00:00:00 2001 From: Madison Date: Fri, 22 Aug 2025 11:47:01 -0500 Subject: [PATCH 02/10] Pointed to MCP server now instead --- docs/src/app/api/chat/route.ts | 151 ++++++++++++++++++--------------- 1 file changed, 84 insertions(+), 67 deletions(-) diff --git a/docs/src/app/api/chat/route.ts b/docs/src/app/api/chat/route.ts index db5dea3d2a..61ccd651c9 100644 --- a/docs/src/app/api/chat/route.ts +++ b/docs/src/app/api/chat/route.ts @@ -1,6 +1,6 @@ import { createGoogleGenerativeAI } from '@ai-sdk/google'; -import { deindent } from '@stackframe/stack-shared/dist/utils/strings'; -import { streamText } from 'ai'; +import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js'; +import { experimental_createMCPClient as createMCPClient, streamText } from 'ai'; // Allow streaming responses up to 30 seconds export const maxDuration = 30; @@ -12,6 +12,7 @@ const google = createGoogleGenerativeAI({ // Helper function to get error message function getErrorMessage(error: unknown): string { + console.log('Error in chat API:', error); if (error instanceof Error) { return error.message; } @@ -19,79 +20,95 @@ function getErrorMessage(error: unknown): string { } export async function POST(request: Request) { - const { messages, docsContent } = await request.json(); + const { messages } = await request.json(); + + // Create MCP client for Stack Auth documentation + const stackAuthMcp = await createMCPClient({ + transport: new StreamableHTTPClientTransport( + new URL('https://mcp.stack-auth.com/api/internal/mcp') + ), + }); + const tools = await stackAuthMcp.tools(); // Create a comprehensive system prompt that restricts AI to Stack Auth topics - const systemPrompt = deindent` - You are Stack Auth's AI assistant. You help users with Stack Auth - a complete authentication and user management solution. - - Think step by step about what to say. Being wrong is 100x worse than saying you don't know. - - CORE RESPONSIBILITIES: - 1. Help users implement Stack Auth in their applications - 2. Answer questions about authentication, user management, and authorization using Stack Auth - 3. Provide guidance on Stack Auth features, configuration, and best practices - 4. Help with framework integrations (Next.js, React, etc.) using Stack Auth - - WHAT TO CONSIDER STACK AUTH-RELATED: - - Authentication implementation in any framework (Next.js, React, etc.) - - User management, registration, login, logout - - Session management and security - - OAuth providers and social auth - - Database configuration and user data - - API routes and middleware - - Authorization and permissions - - Stack Auth configuration and setup - - Troubleshooting authentication issues - - SUPPORT CONTACT INFORMATION: - When users need personalized support, have complex issues, or ask for help beyond what you can provide from the documentation, direct them to: - - **Discord Community**: https://stack-auth.com/discord (best for quick questions and community help) - - **Email Support**: team@stack-auth.com (for technical support and detailed inquiries) - - RESPONSE GUIDELINES: - 1. **Be helpful and proactive**: If a question seems related to authentication or user management, assume it's about Stack Auth - 2. **Ask follow-up questions**: If you need more context to provide a complete answer, ask specific questions like: - - "Are you using Next.js App Router or Pages Router?" - - "What authentication method are you trying to implement?" - - "What specific issue are you encountering?" - 3. **Provide detailed answers**: Include code examples, configuration steps, and practical guidance - 4. **Be humble about limitations**: If you're uncertain about something, say "I don't know" or "I'm not sure" rather than claiming something is "not possible" or "impossible" - 5. **Avoid definitive negative statements**: Instead of saying something can't be done, explain what you're unsure about and suggest alternatives or ask for clarification - 6. **Offer support when appropriate**: If a user has a complex issue, needs personalized help, or you can't fully resolve their problem, suggest contacting support via Discord or email - 7. **Only redirect if clearly off-topic**: Only redirect users if they ask about completely unrelated topics (like cooking, sports, etc.) - - RESPONSE FORMAT: - - Use markdown formatting for better readability - - Include code blocks with proper syntax highlighting - - Use bullet points for lists - - Bold important concepts - - Provide practical examples when possible - - Focus on giving complete, helpful answers - - **DO NOT reference documentation sections or provide links** - - **DO NOT mention checking documentation, guides, or other resources** - - **Provide all necessary information directly in your response** - - WHEN UNSURE: - - If you're unsure about a Stack Auth feature, say "As an AI, I don't know" or "As an AI, I'm not certain" clearly - - Avoid saying things are "not possible" or "impossible", instead say that you don't know - - Ask clarifying questions to better understand the user's needs - - Offer to help with related Stack Auth topics that might be useful - - Provide the best information you can based on your knowledge, but acknowledge limitations - - If the issue is complex or requires personalized assistance, direct them to Discord or email support - - Remember: You're here to help users succeed with Stack Auth. Be helpful, ask questions when needed, provide comprehensive guidance for authentication and user management, and don't hesitate to direct users to support channels when they need additional help. - - DOCUMENTATION CONTEXT: - ${docsContent || 'Documentation not available'} + const systemPrompt = ` +# Stack Auth AI Assistant System Prompt + +You are Stack Auth's AI assistant. You help users with Stack Auth - a complete authentication and user management solution. + +**CRITICAL**: Keep responses SHORT and concise. ALWAYS use the available tools to pull relevant documentation for every question. There should almost never be a question where you don't retrieve relevant docs. + +Think step by step about what to say. Being wrong is 100x worse than saying you don't know. + +## CORE RESPONSIBILITIES: +1. Help users implement Stack Auth in their applications +2. Answer questions about authentication, user management, and authorization using Stack Auth +3. Provide guidance on Stack Auth features, configuration, and best practices +4. Help with framework integrations (Next.js, React, etc.) using Stack Auth + +## WHAT TO CONSIDER STACK AUTH-RELATED: +- Authentication implementation in any framework (Next.js, React, etc.) +- User management, registration, login, logout +- Session management and security +- OAuth providers and social auth +- Database configuration and user data +- API routes and middleware +- Authorization and permissions +- Stack Auth configuration and setup +- Troubleshooting authentication issues + +## SUPPORT CONTACT INFORMATION: +When users need personalized support, have complex issues, or ask for help beyond what you can provide from the documentation, direct them to: +- **Discord Community**: https://discord.stack-auth.com (best for quick questions and community help) +- **Email Support**: team@stack-auth.com (for technical support and detailed inquiries) + +## RESPONSE GUIDELINES: +1. Be concise and direct. Only provide detailed explanations when specifically requested +2. For every question, use the available tools to retrieve the most relevant documentation sections +3. If you're uncertain, say "I don't know" rather than making definitive negative statements +4. For complex issues or personalized help, suggest Discord or email support + +## RESPONSE FORMAT: +- Use markdown formatting for better readability +- Include code blocks with proper syntax highlighting +- Use bullet points for lists +- Bold important concepts +- Provide practical examples when possible +- Focus on giving complete, helpful answers +- **When referencing documentation, use links with the base URL: https://docs.stack-auth.com** +- Example: For setup docs, use https://docs.stack-auth.com/docs/next/getting-started/setup + +## WHEN UNSURE: +- If you're unsure about a Stack Auth feature, say "As an AI, I don't know" or "As an AI, I'm not certain" clearly +- Avoid saying things are "not possible" or "impossible", instead say that you don't know +- Ask clarifying questions to better understand the user's needs +- Offer to help with related Stack Auth topics that might be useful +- Provide the best information you can based on your knowledge, but acknowledge limitations +- If the issue is complex or requires personalized assistance, direct them to Discord or email support + +## KEY STACK AUTH CONCEPTS TO REMEMBER: +- The core philosophy is complete authentication and user management +- All features work together - authentication, user management, teams, permissions +- Built for modern frameworks like Next.js, React, and more +- Supports multiple authentication methods: OAuth, email/password, magic links +- Team and permission management for multi-tenant applications + +## MANDATORY BEHAVIOR: +This is not optional - retrieve relevant documentation for every question. +- Be direct and to the point. Only elaborate when users specifically ask for more detail. + +Remember: You're here to help users succeed with Stack Auth. Be helpful but concise, ask questions when needed, always pull relevant docs, and don't hesitate to direct users to support channels when they need additional help. `; try { const result = streamText({ - model: google('gemini-2.0-flash'), + model: google('gemini-2.5-flash'), + tools: { + ...tools, + }, + maxSteps: 50, system: systemPrompt, messages, - maxTokens: 1500, temperature: 0.1, }); From b93ceecd8a5063e858954bcf30626f7b7831227b Mon Sep 17 00:00:00 2001 From: Madison Date: Fri, 22 Aug 2025 11:47:39 -0500 Subject: [PATCH 03/10] Updated UI to work with new mcp server, and include links within the chat to docs --- docs/src/components/chat/ai-chat.tsx | 245 ++++++++++-------- .../src/components/chat/message-formatter.tsx | 11 +- 2 files changed, 152 insertions(+), 104 deletions(-) diff --git a/docs/src/components/chat/ai-chat.tsx b/docs/src/components/chat/ai-chat.tsx index 42739a000d..075490ee87 100644 --- a/docs/src/components/chat/ai-chat.tsx +++ b/docs/src/components/chat/ai-chat.tsx @@ -1,8 +1,8 @@ 'use client'; import { useChat } from '@ai-sdk/react'; -import { Maximize2, Minimize2, Send, X } from 'lucide-react'; -import { useEffect, useState } from 'react'; +import { ExternalLink, FileText, Maximize2, Minimize2, Send, X } from 'lucide-react'; +import { useEffect, useRef, useState } from 'react'; import { useSidebar } from '../layouts/sidebar-context'; import { MessageFormatter } from './message-formatter'; @@ -22,6 +22,53 @@ function StackIcon({ size = 20, className }: { size?: number, className?: string ); } +// Component to render tool calls +const ToolCallDisplay = ({ + toolCall, +}: { + toolCall: { + toolName: string, + args?: { id?: string }, + result?: { content: { text: string }[] }, + }, +}) => { + if (toolCall.toolName === "get_docs_by_id") { + const docId = toolCall.args?.id; + let docTitle = "Loading..."; + + if (toolCall.result) { + console.log("TOOL CALL RESULT:", toolCall.result); + const newDocTitle = + toolCall.result.content[0].text.match(/Title:\s*(.*)/); + if (newDocTitle && newDocTitle[1]) { + docTitle = newDocTitle[1].trim(); + } + } + + return ( +
+ + + {docTitle} + + {docId && ( + + + Open + + )} +
+ ); + } + + return null; +}; + export function AIChatDrawer() { const sidebarContext = useSidebar(); const { isChatOpen, isChatExpanded, toggleChat, setChatExpanded } = sidebarContext || { @@ -31,7 +78,8 @@ export function AIChatDrawer() { setChatExpanded: () => {}, }; - const [docsContent, setDocsContent] = useState(''); + const editableRef = useRef(null); + const messagesEndRef = useRef(null); const [isHomePage, setIsHomePage] = useState(false); const [isScrolled, setIsScrolled] = useState(false); const [pageLoadTime] = useState(Date.now()); @@ -125,57 +173,6 @@ export function AIChatDrawer() { }; }, []); - // Fetch documentation content when component mounts with caching - useEffect(() => { - let isCancelled = false; - - const fetchDocs = async () => { - try { - // Check cache first (10 minute TTL) - if (typeof window !== 'undefined') { - const cached = sessionStorage.getItem('ai-chat-docs-cache'); - if (cached) { - const { content, timestamp } = JSON.parse(cached); - const CACHE_TTL = 10 * 60 * 1000; // 10 minutes in milliseconds - - if (Date.now() - timestamp < CACHE_TTL) { - // Cache is still valid, use cached content - if (!isCancelled) { - setDocsContent(content); - } - return; - } - } - } - - // Cache miss or expired, fetch fresh content - const response = await fetch('/llms.txt'); - if (response.ok && !isCancelled) { - const content = await response.text(); - setDocsContent(content); - - // Cache the fresh content - if (typeof window !== 'undefined') { - sessionStorage.setItem('ai-chat-docs-cache', JSON.stringify({ - content, - timestamp: Date.now() - })); - } - } - } catch (error) { - console.error('Failed to fetch documentation:', error); - } - }; - - // eslint-disable-next-line no-restricted-syntax - fetchDocs().catch((error) => { - console.error('Failed to fetch documentation:', error); - }); - - return () => { - isCancelled = true; - }; - }, []); // Calculate position based on homepage and scroll state const topPosition = isHomePage && isScrolled ? 'top-0' : 'top-14'; @@ -191,9 +188,6 @@ export function AIChatDrawer() { } = useChat({ api: '/api/chat', initialMessages: [], - body: { - docsContent, - }, onError: (error: Error) => { console.error('Chat error:', error); }, @@ -206,6 +200,20 @@ export function AIChatDrawer() { }, }); + // Auto-scroll to bottom when new messages are added + useEffect(() => { + if (messagesEndRef.current) { + messagesEndRef.current.scrollIntoView({ behavior: 'smooth' }); + } + }, [messages]); + + // Sync contentEditable with input state + useEffect(() => { + if (editableRef.current && editableRef.current.textContent !== input) { + editableRef.current.textContent = input; + } + }, [input]); + // Function to send AI response to Discord webhook const sendAIResponseToDiscord = async (response: string) => { try { @@ -286,25 +294,6 @@ export function AIChatDrawer() { handleSubmit(e); }; - // Non-async wrapper for form onSubmit to avoid promise issues - const handleFormSubmit = (e: React.FormEvent) => { - // eslint-disable-next-line no-restricted-syntax - handleChatSubmit(e).catch(error => { - console.error('Chat submit error:', error); - }); - }; - - // Non-async handler for onKeyDown to avoid promise issues - const handleKeyDown = (e: React.KeyboardEvent) => { - if (e.key === 'Enter' && !e.shiftKey) { - e.preventDefault(); - // eslint-disable-next-line no-restricted-syntax - handleChatSubmit(e as React.FormEvent).catch(error => { - console.error('Chat submit error:', error); - }); - } - }; - // Starter prompts for users const starterPrompts = [ { @@ -421,7 +410,12 @@ export function AIChatDrawer() { {message.content} ) : ( - + <> + {message.toolInvocations?.map((toolCall, index) => ( + + ))} + + )} @@ -430,14 +424,18 @@ export function AIChatDrawer() { {isLoading && (
-
-
-
-
-
-
+
+
+
+ + Thinking +
+
+
+
+
+
- Thinking...
@@ -448,28 +446,69 @@ export function AIChatDrawer() { Error: {error.message}
)} + + {/* Invisible element to scroll to */} +
{/* Input */} -
-
-