Skip to content
19 changes: 13 additions & 6 deletions apps/playground/src/app/api/canvas/generate/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export const maxDuration = 300;
interface CanvasGenerateBody {
prompt: string;
model?: string;
apiKey?: string;
}

export async function POST(req: Request) {
Expand All @@ -30,7 +31,10 @@ export async function POST(req: Request) {
status: 400,
});
}
const { prompt, model } = body;
const prompt = typeof body.prompt === "string" ? body.prompt.trim() : "";
const model = typeof body.model === "string" ? body.model.trim() : undefined;
const apiKey =
typeof body.apiKey === "string" ? body.apiKey.trim() : undefined;
const systemPrompt = catalog.prompt();

if (!prompt) {
Expand All @@ -39,12 +43,15 @@ export async function POST(req: Request) {
});
}

const headerApiKey = req.headers.get("x-llmgateway-key")?.trim() || undefined;

const cookieStore = await cookies();
const cookieApiKey =
cookieStore.get("llmgateway_playground_key")?.value ??
cookieStore.get("__Host-llmgateway_playground_key")?.value;
cookieStore.get("llmgateway_playground_key")?.value.trim() ||
cookieStore.get("__Host-llmgateway_playground_key")?.value.trim();
const finalApiKey = apiKey || headerApiKey || cookieApiKey;

if (!cookieApiKey) {
if (!finalApiKey) {
return new Response(JSON.stringify({ error: "Missing API key" }), {
status: 400,
});
Expand All @@ -57,14 +64,14 @@ export async function POST(req: Request) {
: "https://api.llmgateway.io/v1");

const llmgateway = createLLMGateway({
apiKey: cookieApiKey,
apiKey: finalApiKey,
baseURL: gatewayUrl,
headers: {
"x-source": "chat.llmgateway.io",
},
});

const selectedModel = model ?? "anthropic/claude-sonnet-4-20250514";
const selectedModel = model || "anthropic/claude-sonnet-4-20250514";

const result = streamText({
model: llmgateway.chat(
Expand Down
10 changes: 9 additions & 1 deletion apps/playground/src/app/canvas/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ import { LastUsedProjectTracker } from "@/components/last-used-project-tracker";
import CanvasPageClient from "@/components/playground/canvas-page-client";
import { PlaygroundSeoSection } from "@/components/seo/playground-seo-section";
import { fetchModels, fetchProviders } from "@/lib/fetch-models";
import {
CANVAS_MODEL_COOKIE,
decodeModelPreference,
} from "@/lib/model-preferences";
import { fetchServerData } from "@/lib/server-api";

import type { Project, Organization } from "@/lib/types";
Expand All @@ -23,6 +27,10 @@ export default async function CanvasPage({
searchParams: Promise<{ orgId: string; projectId: string }>;
}) {
const { orgId, projectId } = await searchParams;
const cookieStore = await cookies();
const initialModelPreference = decodeModelPreference(
cookieStore.get(CANVAS_MODEL_COOKIE)?.value,
);

const [models, providers] = await Promise.all([
fetchModels(),
Expand Down Expand Up @@ -92,7 +100,6 @@ export default async function CanvasPage({
notFound();
}
} else if (selectedOrganization?.id) {
const cookieStore = await cookies();
const cookieName = `llmgateway-last-used-project-${selectedOrganization.id}`;
const lastUsed = cookieStore.get(cookieName)?.value;
if (lastUsed) {
Expand All @@ -117,6 +124,7 @@ export default async function CanvasPage({
selectedOrganization={selectedOrganization}
projects={projects}
selectedProject={selectedProject}
initialModelPreference={initialModelPreference}
/>
</>
);
Expand Down
10 changes: 9 additions & 1 deletion apps/playground/src/app/image/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ import { LastUsedProjectTracker } from "@/components/last-used-project-tracker";
import ImagePageClient from "@/components/playground/image-page-client";
import { PlaygroundSeoSection } from "@/components/seo/playground-seo-section";
import { fetchModels, fetchProviders } from "@/lib/fetch-models";
import {
decodeModelPreference,
IMAGE_MODEL_COOKIE,
} from "@/lib/model-preferences";
import { fetchServerData } from "@/lib/server-api";

import type { Project, Organization } from "@/lib/types";
Expand All @@ -23,6 +27,10 @@ export default async function ImagePage({
searchParams: Promise<{ orgId: string; projectId: string }>;
}) {
const { orgId, projectId } = await searchParams;
const cookieStore = await cookies();
const initialModelPreference = decodeModelPreference(
cookieStore.get(IMAGE_MODEL_COOKIE)?.value,
);

const [models, providers] = await Promise.all([
fetchModels(),
Expand Down Expand Up @@ -107,7 +115,6 @@ export default async function ImagePage({
notFound();
}
} else if (selectedOrganization?.id) {
const cookieStore = await cookies();
const cookieName = `llmgateway-last-used-project-${selectedOrganization.id}`;
const lastUsed = cookieStore.get(cookieName)?.value;
if (lastUsed) {
Expand All @@ -132,6 +139,7 @@ export default async function ImagePage({
selectedOrganization={selectedOrganization}
projects={projects}
selectedProject={selectedProject}
initialModelPreference={initialModelPreference}
/>
</>
);
Expand Down
10 changes: 9 additions & 1 deletion apps/playground/src/app/playground-shell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ import ChatPageClient from "@/components/playground/chat-page-client";
import OrgPageClient from "@/components/playground/org-page-client";
import { PlaygroundSeoSection } from "@/components/seo/playground-seo-section";
import { fetchModels, fetchProviders } from "@/lib/fetch-models";
import {
CHAT_MODEL_COOKIE,
decodeModelPreference,
} from "@/lib/model-preferences";
import { fetchServerData } from "@/lib/server-api";

import type { Organization, Project } from "@/lib/types";
Expand Down Expand Up @@ -42,6 +46,10 @@ export async function renderPlaygroundShell({
const orgId = orgShareView?.organizationId ?? searchParams.orgId;
const { projectId } = searchParams;
let { model } = searchParams;
const cookieStore = await cookies();
const initialModelPreference = decodeModelPreference(
cookieStore.get(CHAT_MODEL_COOKIE)?.value,
);

if (hints === "search" && !model) {
model = "google-ai-studio/gemini-3-flash-preview";
Expand Down Expand Up @@ -150,7 +158,6 @@ export async function renderPlaygroundShell({
notFound();
}
} else if (selectedOrganization?.id) {
const cookieStore = await cookies();
const cookieName = `llmgateway-last-used-project-${selectedOrganization.id}`;
const lastUsed = cookieStore.get(cookieName)?.value;
if (lastUsed) {
Expand Down Expand Up @@ -191,6 +198,7 @@ export async function renderPlaygroundShell({
selectedProject={selectedProject}
initialPrompt={q}
enableWebSearch={hints === "search"}
initialModelPreference={initialModelPreference}
/>
</>
);
Expand Down
10 changes: 9 additions & 1 deletion apps/playground/src/app/video/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ import { LastUsedProjectTracker } from "@/components/last-used-project-tracker";
import VideoPageClient from "@/components/playground/video-page-client";
import { PlaygroundSeoSection } from "@/components/seo/playground-seo-section";
import { fetchModels, fetchProviders } from "@/lib/fetch-models";
import {
decodeModelPreference,
VIDEO_MODEL_COOKIE,
} from "@/lib/model-preferences";
import { fetchServerData } from "@/lib/server-api";

import type { Project, Organization } from "@/lib/types";
Expand All @@ -23,6 +27,10 @@ export default async function VideoPage({
searchParams: Promise<{ orgId: string; projectId: string }>;
}) {
const { orgId, projectId } = await searchParams;
const cookieStore = await cookies();
const initialModelPreference = decodeModelPreference(
cookieStore.get(VIDEO_MODEL_COOKIE)?.value,
);

const [models, providers] = await Promise.all([
fetchModels(),
Expand Down Expand Up @@ -107,7 +115,6 @@ export default async function VideoPage({
notFound();
}
} else if (selectedOrganization?.id) {
const cookieStore = await cookies();
const cookieName = `llmgateway-last-used-project-${selectedOrganization.id}`;
const lastUsed = cookieStore.get(cookieName)?.value;
if (lastUsed) {
Expand All @@ -132,6 +139,7 @@ export default async function VideoPage({
selectedOrganization={selectedOrganization}
projects={projects}
selectedProject={selectedProject}
initialModelPreference={initialModelPreference}
/>
</>
);
Expand Down
Loading
Loading