Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
24 changes: 13 additions & 11 deletions app/api/analyze-edit-intent/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,28 +7,30 @@ import { generateObject } from 'ai';
import { z } from 'zod';
// import type { FileManifest } from '@/types/file-manifest'; // Type is used implicitly through manifest parameter

// Check if we're using Vercel AI Gateway
const isUsingAIGateway = !!process.env.AI_GATEWAY_API_KEY;
const aiGatewayBaseURL = 'https://ai-gateway.vercel.sh/v1';
// Custom AI Gateway configuration
// Use custom gateway if API key and base URL are set via environment variables
const customGatewayKey = process.env.AI_GATEWAY_API_KEY || '';
const customGatewayURL = process.env.AI_GATEWAY_BASE_URL || '';
const isUsingAIGateway = !!customGatewayKey && !!customGatewayURL;

const groq = createGroq({
apiKey: process.env.AI_GATEWAY_API_KEY ?? process.env.GROQ_API_KEY,
baseURL: isUsingAIGateway ? aiGatewayBaseURL : undefined,
apiKey: isUsingAIGateway ? customGatewayKey : process.env.GROQ_API_KEY,
baseURL: isUsingAIGateway ? customGatewayURL : undefined,
});

const anthropic = createAnthropic({
apiKey: process.env.AI_GATEWAY_API_KEY ?? process.env.ANTHROPIC_API_KEY,
baseURL: isUsingAIGateway ? aiGatewayBaseURL : (process.env.ANTHROPIC_BASE_URL || 'https://api.anthropic.com/v1'),
apiKey: isUsingAIGateway ? customGatewayKey : process.env.ANTHROPIC_API_KEY,
baseURL: isUsingAIGateway ? customGatewayURL : (process.env.ANTHROPIC_BASE_URL || 'https://api.anthropic.com/v1'),
});

const openai = createOpenAI({
apiKey: process.env.AI_GATEWAY_API_KEY ?? process.env.OPENAI_API_KEY,
baseURL: isUsingAIGateway ? aiGatewayBaseURL : process.env.OPENAI_BASE_URL,
apiKey: isUsingAIGateway ? customGatewayKey : process.env.OPENAI_API_KEY,
baseURL: isUsingAIGateway ? customGatewayURL : process.env.OPENAI_BASE_URL,
});

const googleGenerativeAI = createGoogleGenerativeAI({
apiKey: process.env.AI_GATEWAY_API_KEY ?? process.env.GEMINI_API_KEY,
baseURL: isUsingAIGateway ? aiGatewayBaseURL : undefined,
apiKey: isUsingAIGateway ? customGatewayKey : process.env.GEMINI_API_KEY,
baseURL: isUsingAIGateway ? customGatewayURL : undefined,
});

// Schema for the AI's search plan - not file selection!
Expand Down
45 changes: 32 additions & 13 deletions app/api/generate-ai-code-stream/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,34 +14,39 @@ import { appConfig } from '@/config/app.config';
// Force dynamic route to enable streaming
export const dynamic = 'force-dynamic';

// Check if we're using Vercel AI Gateway
const isUsingAIGateway = !!process.env.AI_GATEWAY_API_KEY;
const aiGatewayBaseURL = 'https://ai-gateway.vercel.sh/v1';
// Custom AI Gateway configuration
// Use custom gateway if API key and base URL are set via environment variables
const customGatewayKey = process.env.AI_GATEWAY_API_KEY || '';
const customGatewayURL = process.env.AI_GATEWAY_BASE_URL || '';
const isUsingAIGateway = !!customGatewayKey && !!customGatewayURL;

console.log('[generate-ai-code-stream] AI Gateway config:', {
isUsingAIGateway,
gatewayURL: customGatewayURL,
hasGroqKey: !!process.env.GROQ_API_KEY,
hasAIGatewayKey: !!process.env.AI_GATEWAY_API_KEY
hasAIGatewayKey: !!customGatewayKey
});

// When using AI Gateway, set baseURL to AI Gateway endpoint
// AI Gateway will route requests to the correct provider based on model name
const groq = createGroq({
apiKey: process.env.AI_GATEWAY_API_KEY ?? process.env.GROQ_API_KEY,
baseURL: isUsingAIGateway ? aiGatewayBaseURL : undefined,
apiKey: isUsingAIGateway ? customGatewayKey : process.env.GROQ_API_KEY,
baseURL: isUsingAIGateway ? customGatewayURL : undefined,
});

const anthropic = createAnthropic({
apiKey: process.env.AI_GATEWAY_API_KEY ?? process.env.ANTHROPIC_API_KEY,
baseURL: isUsingAIGateway ? aiGatewayBaseURL : (process.env.ANTHROPIC_BASE_URL || 'https://api.anthropic.com/v1'),
apiKey: isUsingAIGateway ? customGatewayKey : process.env.ANTHROPIC_API_KEY,
baseURL: isUsingAIGateway ? customGatewayURL : (process.env.ANTHROPIC_BASE_URL || 'https://api.anthropic.com/v1'),
});

const googleGenerativeAI = createGoogleGenerativeAI({
apiKey: process.env.AI_GATEWAY_API_KEY ?? process.env.GEMINI_API_KEY,
baseURL: isUsingAIGateway ? aiGatewayBaseURL : undefined,
apiKey: isUsingAIGateway ? customGatewayKey : process.env.GEMINI_API_KEY,
baseURL: isUsingAIGateway ? customGatewayURL : undefined,
});

const openai = createOpenAI({
apiKey: process.env.AI_GATEWAY_API_KEY ?? process.env.OPENAI_API_KEY,
baseURL: isUsingAIGateway ? aiGatewayBaseURL : process.env.OPENAI_BASE_URL,
apiKey: isUsingAIGateway ? customGatewayKey : process.env.OPENAI_API_KEY,
baseURL: isUsingAIGateway ? customGatewayURL : process.env.OPENAI_BASE_URL,
});

// Helper function to analyze user preferences from conversation history
Expand Down Expand Up @@ -1223,8 +1228,22 @@ MORPH FAST APPLY MODE (EDIT-ONLY):
(isKimiGroq ? groq : groq)));

// Fix model name transformation for different providers
// Custom AI Gateway requires model names without prefix (e.g., 'gpt-5' instead of 'openai/gpt-5')
let actualModel: string;
if (isAnthropic) {
if (isUsingAIGateway) {
// Custom Gateway requires model names without prefix
if (isAnthropic) {
actualModel = model.replace('anthropic/', '');
} else if (isOpenAI) {
actualModel = model.replace('openai/', '');
} else if (isGoogle) {
actualModel = model.replace('google/', '');
} else if (isKimiGroq) {
actualModel = 'moonshotai/kimi-k2-instruct-0905';
} else {
actualModel = model;
}
} else if (isAnthropic) {
actualModel = model.replace('anthropic/', '');
} else if (isOpenAI) {
actualModel = model.replace('openai/', '');
Expand Down
12 changes: 6 additions & 6 deletions app/generation/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1244,7 +1244,7 @@ Tip: I automatically detect and install npm packages from your code imports (lik
{fileInfo.name}
{fileInfo.edited && (
<span className={`text-[10px] px-1 rounded ${
isSelected ? 'bg-blue-400' : 'bg-orange-500 text-white'
isSelected ? 'bg-blue-400' : 'bg-black text-white'
}`}>✓</span>
)}
</span>
Expand Down Expand Up @@ -1361,7 +1361,7 @@ Tip: I automatically detect and install npm packages from your code imports (lik
<div className="bg-black border border-gray-200 rounded-lg overflow-hidden">
<div className="px-4 py-2 bg-gray-100 text-gray-900 flex items-center justify-between">
<div className="flex items-center gap-2">
<div className="w-16 h-16 border-2 border-orange-500 border-t-transparent rounded-full animate-spin" />
<div className="w-16 h-16 border-2 border-black border-t-transparent rounded-full animate-spin" />
<span className="font-mono text-sm">Streaming code...</span>
</div>
</div>
Expand All @@ -1379,7 +1379,7 @@ Tip: I automatically detect and install npm packages from your code imports (lik
>
{generationProgress.streamedCode || 'Starting code generation...'}
</SyntaxHighlighter>
<span className="inline-block w-3 h-5 bg-orange-400 ml-1 animate-pulse" />
<span className="inline-block w-3 h-5 bg-gray-700 ml-1 animate-pulse" />
</div>
</div>
)
Expand Down Expand Up @@ -1421,7 +1421,7 @@ Tip: I automatically detect and install npm packages from your code imports (lik
>
{generationProgress.currentFile.content}
</SyntaxHighlighter>
<span className="inline-block w-3 h-4 bg-orange-400 ml-4 mb-4 animate-pulse" />
<span className="inline-block w-3 h-4 bg-gray-700 ml-4 mb-4 animate-pulse" />
</div>
</div>
)}
Expand Down Expand Up @@ -1516,7 +1516,7 @@ Tip: I automatically detect and install npm packages from your code imports (lik
<div className="mx-6 mb-6">
<div className="h-2 bg-gray-200 rounded-full overflow-hidden">
<div
className="h-full bg-gradient-to-r from-orange-500 to-orange-400 transition-all duration-300"
className="h-full bg-gradient-to-r from-black to-gray-700 transition-all duration-300"
style={{
width: `${(generationProgress.currentComponent / Math.max(generationProgress.components.length, 1)) * 100}%`
}}
Expand Down Expand Up @@ -3837,7 +3837,7 @@ Focus on the key sections and content, making it clean and modern.`;
return startIndex !== -1 ? lastContent.slice(startIndex) : lastContent;
})()}
</SyntaxHighlighter>
<span className="inline-block w-3 h-4 bg-orange-400 ml-3 mb-3 animate-pulse" />
<span className="inline-block w-3 h-4 bg-gray-700 ml-3 mb-3 animate-pulse" />
</div>
</motion.div>
)}
Expand Down
71 changes: 70 additions & 1 deletion app/globals.css
Original file line number Diff line number Diff line change
@@ -1 +1,70 @@
@import "../styles/main.css";
@tailwind base;
@tailwind components;
@tailwind utilities;

@layer base {
:root {
/* Vercel Light Theme */
--background: #FAFAFA;
--foreground: #000000;
--muted: #F5F5F5;
--muted-foreground: #737373;
--border: #E5E5E5;
--input: #E5E5E5;
--ring: #000000;
--radius: 6px;

/* Shadcn compatibility */
--primary: 0 0% 0%;
--primary-foreground: 0 0% 100%;
--secondary: 0 0% 96%;
--secondary-foreground: 0 0% 0%;
--accent: 221 83% 53%;
--accent-foreground: 0 0% 100%;
--destructive: 0 84% 60%;
--destructive-foreground: 0 0% 100%;
--card: 0 0% 100%;
--card-foreground: 0 0% 0%;
--popover: 0 0% 100%;
--popover-foreground: 0 0% 0%;
}

.dark {
--background: #000000;
--foreground: #FFFFFF;
--muted: #171717;
--muted-foreground: #A3A3A3;
--border: #262626;
--input: #262626;
--ring: #FFFFFF;

--primary: 0 0% 100%;
--primary-foreground: 0 0% 0%;
--secondary: 0 0% 15%;
--secondary-foreground: 0 0% 100%;
}

* {
@apply border-border;
}

body {
@apply bg-background text-foreground;
font-family: var(--font-geist-sans);
font-feature-settings: 'rlig' 1, 'calt' 1;
}
}

@layer utilities {
.text-secondary {
color: #737373;
}

.bg-surface {
background-color: #FFFFFF;
}

.transition-vercel {
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}
}
27 changes: 0 additions & 27 deletions app/landing.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,12 @@ import { HeaderProvider } from "@/components/shared/header/HeaderContext";
// import HeaderBrandKit from "@/components/shared/header/BrandKit/BrandKit"; // Not used in current implementation
import HeaderWrapper from "@/components/shared/header/Wrapper/Wrapper";
import HeaderDropdownWrapper from "@/components/shared/header/Dropdown/Wrapper/Wrapper";
import ButtonUI from "@/components/ui/shadcn/button";

// Import hero section components
import HomeHeroBackground from "@/components/app/(home)/sections/hero/Background/Background";
import { BackgroundOuterPiece } from "@/components/app/(home)/sections/hero/Background/BackgroundOuterPiece";
import HomeHeroBadge from "@/components/app/(home)/sections/hero/Badge/Badge";
import HomeHeroPixi from "@/components/app/(home)/sections/hero/Pixi/Pixi";
import HomeHeroTitle from "@/components/app/(home)/sections/hero/Title/Title";
import HeroInput from "@/components/app/(home)/sections/hero-input/HeroInput";
import { Connector } from "@/components/shared/layout/curvy-rect";
import HeroFlame from "@/components/shared/effects/flame/hero-flame";
import FirecrawlIcon from "@/components/FirecrawlIcon";
import FirecrawlLogo from "@/components/FirecrawlLogo";

Expand All @@ -32,11 +27,6 @@ export default function LandingPage() {
<div className="sticky top-0 left-0 w-full z-[101] bg-background-base header">
<div className="absolute top-0 cmw-container border-x border-border-faint h-full pointer-events-none" />
<div className="h-1 bg-border-faint w-full left-0 -bottom-1 absolute" />

<div className="cmw-container absolute h-full pointer-events-none top-0">
<Connector className="absolute -left-[10.5px] -bottom-11" />
<Connector className="absolute -right-[10.5px] -bottom-11" />
</div>

<HeaderWrapper>
<div className="max-w-[900px] mx-auto w-full flex justify-between items-center">
Expand All @@ -47,30 +37,13 @@ export default function LandingPage() {
</Link>
</div>

<div className="flex gap-8">
<Link
href="https://github.com/mendableai/open-lovable"
target="_blank"
className="contents"
>
<ButtonUI variant="tertiary">
<svg className="w-4 h-4" fill="currentColor" viewBox="0 0 24 24">
<path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/>
</svg>
Use this Template
</ButtonUI>
</Link>
</div>
</div>
</HeaderWrapper>
</div>

{/* Hero Section */}
<section className="overflow-x-clip" id="home-hero">
<div className="pt-28 lg:pt-254 lg:-mt-100 pb-115 relative" id="hero-content">
<HomeHeroPixi />
<HeroFlame />
<BackgroundOuterPiece />
<HomeHeroBackground />

<div className="relative container px-16">
Expand Down
Loading