├── app ├── favicon.ico ├── opengraph-image.png ├── twitter-image.png ├── page.tsx ├── globals.css ├── api │ └── chat │ │ └── route.ts └── layout.tsx ├── .env.example ├── public ├── vercel.svg ├── window.svg ├── file.svg ├── globe.svg └── next.svg ├── postcss.config.mjs ├── next.config.ts ├── eslint.config.mjs ├── tailwind.config.ts ├── .gitignore ├── tsconfig.json ├── components ├── footnote.tsx ├── deploy-button.tsx ├── input.tsx ├── star-button.tsx ├── messages.tsx ├── icons.tsx └── chat.tsx ├── lib └── models.ts ├── package.json └── README.md /app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vercel-labs/ai-sdk-reasoning-starter/HEAD/app/favicon.ico -------------------------------------------------------------------------------- /app/opengraph-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vercel-labs/ai-sdk-reasoning-starter/HEAD/app/opengraph-image.png -------------------------------------------------------------------------------- /app/twitter-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vercel-labs/ai-sdk-reasoning-starter/HEAD/app/twitter-image.png -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | # Get your Anthropic API Key here: https://docs.anthropic.com/en/api/admin-api/apikeys/get-api-key 2 | ANTHROPIC_API_KEY=**** 3 | -------------------------------------------------------------------------------- /public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /postcss.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('postcss-load-config').Config} */ 2 | const config = { 3 | plugins: { 4 | tailwindcss: {}, 5 | }, 6 | }; 7 | 8 | export default config; 9 | -------------------------------------------------------------------------------- /app/page.tsx: -------------------------------------------------------------------------------- 1 | import { Chat } from "@/components/chat"; 2 | 3 | export default function Home() { 4 | return ( 5 |
6 | 7 |
8 | ); 9 | } 10 | -------------------------------------------------------------------------------- /next.config.ts: -------------------------------------------------------------------------------- 1 | import type { NextConfig } from 'next'; 2 | 3 | const nextConfig: NextConfig = { 4 | transpilePackages: ['geist'], 5 | images: { 6 | remotePatterns: [ 7 | { 8 | hostname: 'vercel.com', 9 | }, 10 | ], 11 | }, 12 | }; 13 | 14 | export default nextConfig; 15 | -------------------------------------------------------------------------------- /public/window.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/file.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | :root { 6 | --background: #ffffff; 7 | --foreground: #171717; 8 | } 9 | 10 | @media (prefers-color-scheme: dark) { 11 | :root { 12 | --background: #0a0a0a; 13 | --foreground: #ededed; 14 | } 15 | } 16 | 17 | body { 18 | color: var(--foreground); 19 | background: var(--background); 20 | } 21 | -------------------------------------------------------------------------------- /eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import { dirname } from "path"; 2 | import { fileURLToPath } from "url"; 3 | import { FlatCompat } from "@eslint/eslintrc"; 4 | 5 | const __filename = fileURLToPath(import.meta.url); 6 | const __dirname = dirname(__filename); 7 | 8 | const compat = new FlatCompat({ 9 | baseDirectory: __dirname, 10 | }); 11 | 12 | const eslintConfig = [ 13 | ...compat.extends("next/core-web-vitals", "next/typescript"), 14 | ]; 15 | 16 | export default eslintConfig; 17 | -------------------------------------------------------------------------------- /tailwind.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from "tailwindcss"; 2 | 3 | export default { 4 | content: [ 5 | "./pages/**/*.{js,ts,jsx,tsx,mdx}", 6 | "./components/**/*.{js,ts,jsx,tsx,mdx}", 7 | "./app/**/*.{js,ts,jsx,tsx,mdx}", 8 | './node_modules/streamdown/dist/*.js', 9 | ], 10 | theme: { 11 | extend: { 12 | colors: { 13 | background: "var(--background)", 14 | foreground: "var(--foreground)", 15 | }, 16 | fontFamily: { 17 | sans: ["var(--font-geist-sans)"], 18 | mono: ["var(--font-geist-mono)"], 19 | }, 20 | }, 21 | }, 22 | plugins: [], 23 | } satisfies Config; 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.* 7 | .yarn/* 8 | !.yarn/patches 9 | !.yarn/plugins 10 | !.yarn/releases 11 | !.yarn/versions 12 | 13 | # testing 14 | /coverage 15 | 16 | # next.js 17 | /.next/ 18 | /out/ 19 | 20 | # production 21 | /build 22 | 23 | # misc 24 | .DS_Store 25 | *.pem 26 | 27 | # debug 28 | npm-debug.log* 29 | yarn-debug.log* 30 | yarn-error.log* 31 | .pnpm-debug.log* 32 | 33 | # env files (can opt-in for committing if needed) 34 | .env* 35 | 36 | # vercel 37 | .vercel 38 | 39 | # typescript 40 | *.tsbuildinfo 41 | next-env.d.ts 42 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2017", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "noEmit": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "jsx": "preserve", 15 | "incremental": true, 16 | "plugins": [ 17 | { 18 | "name": "next" 19 | } 20 | ], 21 | "paths": { 22 | "@/*": ["./*"] 23 | } 24 | }, 25 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 26 | "exclude": ["node_modules"] 27 | } 28 | -------------------------------------------------------------------------------- /components/footnote.tsx: -------------------------------------------------------------------------------- 1 | import Link from 'next/link'; 2 | 3 | export function Footnote() { 4 | return ( 5 |
6 | This preview is built using{' '} 7 | 12 | Next.js 13 | {' '} 14 | and the{' '} 15 | 20 | AI SDK 21 | 22 | . Read more about how to use reasoning models in your applications in our{' '} 23 | 28 | documentation 29 | 30 | . 31 |
32 | ); 33 | } 34 | -------------------------------------------------------------------------------- /public/globe.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /components/deploy-button.tsx: -------------------------------------------------------------------------------- 1 | import Link from "next/link"; 2 | export const DeployButton = () => ( 3 | 9 | 17 | 23 | 24 | Deploy 25 | 26 | ); 27 | -------------------------------------------------------------------------------- /lib/models.ts: -------------------------------------------------------------------------------- 1 | import { anthropic } from "@ai-sdk/anthropic"; 2 | import { fireworks } from "@ai-sdk/fireworks"; 3 | import { groq } from "@ai-sdk/groq"; 4 | import { 5 | customProvider, 6 | extractReasoningMiddleware, 7 | wrapLanguageModel, 8 | } from "ai"; 9 | 10 | // custom provider with different model settings: 11 | export const myProvider = customProvider({ 12 | languageModels: { 13 | "sonnet-3.7": anthropic("claude-3-7-sonnet-20250219"), 14 | "deepseek-r1": wrapLanguageModel({ 15 | middleware: extractReasoningMiddleware({ 16 | tagName: "think", 17 | }), 18 | model: fireworks("accounts/fireworks/models/deepseek-r1"), 19 | }), 20 | "deepseek-r1-distill-llama-70b": wrapLanguageModel({ 21 | middleware: extractReasoningMiddleware({ 22 | tagName: "think", 23 | }), 24 | model: groq("deepseek-r1-distill-llama-70b"), 25 | }), 26 | }, 27 | }); 28 | 29 | export type modelID = Parameters<(typeof myProvider)["languageModel"]>["0"]; 30 | 31 | export const models: Record = { 32 | "sonnet-3.7": "Claude Sonnet 3.7", 33 | "deepseek-r1": "DeepSeek-R1", 34 | "deepseek-r1-distill-llama-70b": "DeepSeek-R1 Llama 70B", 35 | }; 36 | -------------------------------------------------------------------------------- /components/input.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { toast } from "sonner"; 4 | 5 | interface InputProps { 6 | input: string; 7 | setInput: (value: string) => void; 8 | selectedModelId: string; 9 | isGeneratingResponse: boolean; 10 | isReasoningEnabled: boolean; 11 | onSubmit: () => void; 12 | } 13 | 14 | export function Input({ 15 | input, 16 | setInput, 17 | isGeneratingResponse, 18 | onSubmit, 19 | }: InputProps) { 20 | 21 | return ( 22 |