├── 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 |