Date: Fri, 29 Sep 2023 15:51:54 -0700
Subject: [PATCH] feat: add tabby playground for q&a use case (#493)
* init commit
* support chat
* add theme toggle
* limit message to 2 lines
* update
* update formatting
* update
* update
* update
* fix formatting
* update
---
Cargo.lock | 44 +-
Makefile | 5 +
clients/tabby-playground/.env.example | 1 +
clients/tabby-playground/.eslintrc.json | 25 +
clients/tabby-playground/.gitignore | 38 +
clients/tabby-playground/LICENSE | 13 +
clients/tabby-playground/README.md | 73 +
clients/tabby-playground/app/globals.css | 78 +
clients/tabby-playground/app/layout.tsx | 51 +
clients/tabby-playground/app/page.tsx | 8 +
.../assets/fonts/Inter-Bold.woff | Bin 0 -> 25760 bytes
.../assets/fonts/Inter-Regular.woff | Bin 0 -> 24576 bytes
.../components/button-scroll-to-bottom.tsx | 34 +
.../tabby-playground/components/chat-list.tsx | 27 +
.../components/chat-message-actions.tsx | 40 +
.../components/chat-message.tsx | 93 +
.../components/chat-panel.tsx | 78 +
.../components/chat-scroll-anchor.tsx | 29 +
clients/tabby-playground/components/chat.tsx | 69 +
.../components/clear-history.tsx | 73 +
.../components/empty-screen.tsx | 43 +
.../components/external-link.tsx | 29 +
.../tabby-playground/components/footer.tsx | 19 +
.../tabby-playground/components/header.tsx | 33 +
.../components/login-button.tsx | 42 +
.../tabby-playground/components/markdown.tsx | 9 +
.../components/prompt-form.tsx | 88 +
.../tabby-playground/components/providers.tsx | 15 +
.../components/tailwind-indicator.tsx | 14 +
.../components/theme-toggle.tsx | 31 +
.../tabby-playground/components/toaster.tsx | 3 +
.../components/ui/alert-dialog.tsx | 150 +
.../tabby-playground/components/ui/badge.tsx | 36 +
.../tabby-playground/components/ui/button.tsx | 57 +
.../components/ui/codeblock.tsx | 145 +
.../tabby-playground/components/ui/dialog.tsx | 128 +
.../components/ui/dropdown-menu.tsx | 128 +
.../tabby-playground/components/ui/icons.tsx | 507 ++
.../tabby-playground/components/ui/input.tsx | 25 +
.../tabby-playground/components/ui/label.tsx | 26 +
.../tabby-playground/components/ui/select.tsx | 123 +
.../components/ui/separator.tsx | 31 +
.../tabby-playground/components/ui/sheet.tsx | 122 +
.../tabby-playground/components/ui/switch.tsx | 29 +
.../components/ui/textarea.tsx | 24 +
.../components/ui/tooltip.tsx | 30 +
.../tabby-playground/components/user-menu.tsx | 79 +
clients/tabby-playground/lib/analytics.ts | 62 +
clients/tabby-playground/lib/fonts.ts | 11 +
.../lib/hooks/use-at-bottom.tsx | 23 +
.../lib/hooks/use-copy-to-clipboard.tsx | 33 +
.../lib/hooks/use-enter-submit.tsx | 23 +
.../lib/hooks/use-local-storage.ts | 24 +
.../lib/hooks/use-patch-fetch.ts | 39 +
clients/tabby-playground/lib/types.ts | 18 +
clients/tabby-playground/lib/utils.ts | 43 +
clients/tabby-playground/next-env.d.ts | 5 +
clients/tabby-playground/next.config.js | 9 +
clients/tabby-playground/package.json | 68 +
clients/tabby-playground/postcss.config.js | 6 +
clients/tabby-playground/prettier.config.cjs | 34 +
clients/tabby-playground/tailwind.config.js | 96 +
clients/tabby-playground/tsconfig.json | 35 +
clients/tabby-playground/yarn.lock | 4522 +++++++++++++++++
crates/tabby/Cargo.toml | 2 +-
crates/tabby/playground/404.html | 1 +
.../IDbc2tNjcWJDV9VC-wJcu/_buildManifest.js | 1 +
.../IDbc2tNjcWJDV9VC-wJcu/_ssgManifest.js | 1 +
.../static/chunks/346-c4227fa5fd95e485.js | 185 +
.../static/chunks/376.2b6536d53b303d15.js | 1 +
.../static/chunks/524-e377ca48d97ab2b7.js | 1 +
.../static/chunks/864-1669531662d5540a.js | 25 +
.../static/chunks/978-ab68c4a2390585a1.js | 34 +
.../chunks/app/_not-found-58bcddf7b3e44a54.js | 1 +
.../chunks/app/layout-21eaa53709d9db66.js | 1 +
.../chunks/app/page-f0348ea0b604a423.js | 1 +
.../chunks/fd9d1056-5dfc77aa37d8c76f.js | 9 +
.../chunks/framework-43665103d101a22d.js | 25 +
.../static/chunks/main-02b01a461f5aae93.js | 1 +
.../chunks/main-app-63509e933f53c55d.js | 1 +
.../chunks/pages/_app-6ca4a4ec31e39f3d.js | 1 +
.../chunks/pages/_error-9de0d1f4f4d1fcb4.js | 1 +
.../chunks/polyfills-c67a75d1b6f99dc8.js | 1 +
.../static/chunks/webpack-52ce74dd37dd8861.js | 1 +
.../_next/static/css/d091dc2da2a795e4.css | 3 +
.../static/media/05a31a2ca4975f99-s.woff2 | Bin 0 -> 10496 bytes
.../static/media/34dd45dcdd6d47ee-s.woff2 | Bin 0 -> 7240 bytes
.../static/media/513657b02c5c193f-s.woff2 | Bin 0 -> 17612 bytes
.../static/media/51ed15f9841b9f9d-s.woff2 | Bin 0 -> 22524 bytes
.../static/media/86fdec36ddd9097e-s.p.woff2 | Bin 0 -> 39888 bytes
.../static/media/9e58c89b9633dcad-s.woff2 | Bin 0 -> 11824 bytes
.../static/media/a1ab2e69d2f53384-s.woff2 | Bin 0 -> 14428 bytes
.../static/media/c4a41ea065a0023c-s.woff2 | Bin 0 -> 8848 bytes
.../static/media/c9a5bc6a7c948fb0-s.p.woff2 | Bin 0 -> 46552 bytes
.../static/media/d6b16ce4a6175f26-s.woff2 | Bin 0 -> 80044 bytes
.../static/media/de2ba2ebf355004e-s.woff2 | Bin 0 -> 1944 bytes
.../static/media/ec159349637c90ad-s.woff2 | Bin 0 -> 27316 bytes
.../static/media/fd4db3eb5472fc27-s.woff2 | Bin 0 -> 12768 bytes
crates/tabby/playground/index.html | 1 +
crates/tabby/playground/index.txt | 13 +
crates/tabby/src/serve/mod.rs | 3 +
.../src/serve/{admin.rs => playground.rs} | 20 +-
102 files changed, 8116 insertions(+), 14 deletions(-)
create mode 100644 clients/tabby-playground/.env.example
create mode 100644 clients/tabby-playground/.eslintrc.json
create mode 100644 clients/tabby-playground/.gitignore
create mode 100644 clients/tabby-playground/LICENSE
create mode 100644 clients/tabby-playground/README.md
create mode 100644 clients/tabby-playground/app/globals.css
create mode 100644 clients/tabby-playground/app/layout.tsx
create mode 100644 clients/tabby-playground/app/page.tsx
create mode 100644 clients/tabby-playground/assets/fonts/Inter-Bold.woff
create mode 100644 clients/tabby-playground/assets/fonts/Inter-Regular.woff
create mode 100644 clients/tabby-playground/components/button-scroll-to-bottom.tsx
create mode 100644 clients/tabby-playground/components/chat-list.tsx
create mode 100644 clients/tabby-playground/components/chat-message-actions.tsx
create mode 100644 clients/tabby-playground/components/chat-message.tsx
create mode 100644 clients/tabby-playground/components/chat-panel.tsx
create mode 100644 clients/tabby-playground/components/chat-scroll-anchor.tsx
create mode 100644 clients/tabby-playground/components/chat.tsx
create mode 100644 clients/tabby-playground/components/clear-history.tsx
create mode 100644 clients/tabby-playground/components/empty-screen.tsx
create mode 100644 clients/tabby-playground/components/external-link.tsx
create mode 100644 clients/tabby-playground/components/footer.tsx
create mode 100644 clients/tabby-playground/components/header.tsx
create mode 100644 clients/tabby-playground/components/login-button.tsx
create mode 100644 clients/tabby-playground/components/markdown.tsx
create mode 100644 clients/tabby-playground/components/prompt-form.tsx
create mode 100644 clients/tabby-playground/components/providers.tsx
create mode 100644 clients/tabby-playground/components/tailwind-indicator.tsx
create mode 100644 clients/tabby-playground/components/theme-toggle.tsx
create mode 100644 clients/tabby-playground/components/toaster.tsx
create mode 100644 clients/tabby-playground/components/ui/alert-dialog.tsx
create mode 100644 clients/tabby-playground/components/ui/badge.tsx
create mode 100644 clients/tabby-playground/components/ui/button.tsx
create mode 100644 clients/tabby-playground/components/ui/codeblock.tsx
create mode 100644 clients/tabby-playground/components/ui/dialog.tsx
create mode 100644 clients/tabby-playground/components/ui/dropdown-menu.tsx
create mode 100644 clients/tabby-playground/components/ui/icons.tsx
create mode 100644 clients/tabby-playground/components/ui/input.tsx
create mode 100644 clients/tabby-playground/components/ui/label.tsx
create mode 100644 clients/tabby-playground/components/ui/select.tsx
create mode 100644 clients/tabby-playground/components/ui/separator.tsx
create mode 100644 clients/tabby-playground/components/ui/sheet.tsx
create mode 100644 clients/tabby-playground/components/ui/switch.tsx
create mode 100644 clients/tabby-playground/components/ui/textarea.tsx
create mode 100644 clients/tabby-playground/components/ui/tooltip.tsx
create mode 100644 clients/tabby-playground/components/user-menu.tsx
create mode 100644 clients/tabby-playground/lib/analytics.ts
create mode 100644 clients/tabby-playground/lib/fonts.ts
create mode 100644 clients/tabby-playground/lib/hooks/use-at-bottom.tsx
create mode 100644 clients/tabby-playground/lib/hooks/use-copy-to-clipboard.tsx
create mode 100644 clients/tabby-playground/lib/hooks/use-enter-submit.tsx
create mode 100644 clients/tabby-playground/lib/hooks/use-local-storage.ts
create mode 100644 clients/tabby-playground/lib/hooks/use-patch-fetch.ts
create mode 100644 clients/tabby-playground/lib/types.ts
create mode 100644 clients/tabby-playground/lib/utils.ts
create mode 100644 clients/tabby-playground/next-env.d.ts
create mode 100644 clients/tabby-playground/next.config.js
create mode 100644 clients/tabby-playground/package.json
create mode 100644 clients/tabby-playground/postcss.config.js
create mode 100644 clients/tabby-playground/prettier.config.cjs
create mode 100644 clients/tabby-playground/tailwind.config.js
create mode 100644 clients/tabby-playground/tsconfig.json
create mode 100644 clients/tabby-playground/yarn.lock
create mode 100644 crates/tabby/playground/404.html
create mode 100644 crates/tabby/playground/_next/static/IDbc2tNjcWJDV9VC-wJcu/_buildManifest.js
create mode 100644 crates/tabby/playground/_next/static/IDbc2tNjcWJDV9VC-wJcu/_ssgManifest.js
create mode 100644 crates/tabby/playground/_next/static/chunks/346-c4227fa5fd95e485.js
create mode 100644 crates/tabby/playground/_next/static/chunks/376.2b6536d53b303d15.js
create mode 100644 crates/tabby/playground/_next/static/chunks/524-e377ca48d97ab2b7.js
create mode 100644 crates/tabby/playground/_next/static/chunks/864-1669531662d5540a.js
create mode 100644 crates/tabby/playground/_next/static/chunks/978-ab68c4a2390585a1.js
create mode 100644 crates/tabby/playground/_next/static/chunks/app/_not-found-58bcddf7b3e44a54.js
create mode 100644 crates/tabby/playground/_next/static/chunks/app/layout-21eaa53709d9db66.js
create mode 100644 crates/tabby/playground/_next/static/chunks/app/page-f0348ea0b604a423.js
create mode 100644 crates/tabby/playground/_next/static/chunks/fd9d1056-5dfc77aa37d8c76f.js
create mode 100644 crates/tabby/playground/_next/static/chunks/framework-43665103d101a22d.js
create mode 100644 crates/tabby/playground/_next/static/chunks/main-02b01a461f5aae93.js
create mode 100644 crates/tabby/playground/_next/static/chunks/main-app-63509e933f53c55d.js
create mode 100644 crates/tabby/playground/_next/static/chunks/pages/_app-6ca4a4ec31e39f3d.js
create mode 100644 crates/tabby/playground/_next/static/chunks/pages/_error-9de0d1f4f4d1fcb4.js
create mode 100644 crates/tabby/playground/_next/static/chunks/polyfills-c67a75d1b6f99dc8.js
create mode 100644 crates/tabby/playground/_next/static/chunks/webpack-52ce74dd37dd8861.js
create mode 100644 crates/tabby/playground/_next/static/css/d091dc2da2a795e4.css
create mode 100644 crates/tabby/playground/_next/static/media/05a31a2ca4975f99-s.woff2
create mode 100644 crates/tabby/playground/_next/static/media/34dd45dcdd6d47ee-s.woff2
create mode 100644 crates/tabby/playground/_next/static/media/513657b02c5c193f-s.woff2
create mode 100644 crates/tabby/playground/_next/static/media/51ed15f9841b9f9d-s.woff2
create mode 100644 crates/tabby/playground/_next/static/media/86fdec36ddd9097e-s.p.woff2
create mode 100644 crates/tabby/playground/_next/static/media/9e58c89b9633dcad-s.woff2
create mode 100644 crates/tabby/playground/_next/static/media/a1ab2e69d2f53384-s.woff2
create mode 100644 crates/tabby/playground/_next/static/media/c4a41ea065a0023c-s.woff2
create mode 100644 crates/tabby/playground/_next/static/media/c9a5bc6a7c948fb0-s.p.woff2
create mode 100644 crates/tabby/playground/_next/static/media/d6b16ce4a6175f26-s.woff2
create mode 100644 crates/tabby/playground/_next/static/media/de2ba2ebf355004e-s.woff2
create mode 100644 crates/tabby/playground/_next/static/media/ec159349637c90ad-s.woff2
create mode 100644 crates/tabby/playground/_next/static/media/fd4db3eb5472fc27-s.woff2
create mode 100644 crates/tabby/playground/index.html
create mode 100644 crates/tabby/playground/index.txt
rename crates/tabby/src/serve/{admin.rs => playground.rs} (72%)
diff --git a/Cargo.lock b/Cargo.lock
index 20cc422..1acdf4e 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2620,8 +2620,19 @@ version = "6.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b68543d5527e158213414a92832d2aab11a84d2571a5eb021ebe22c43aab066"
dependencies = [
- "rust-embed-impl",
- "rust-embed-utils",
+ "rust-embed-impl 6.5.0",
+ "rust-embed-utils 7.5.0",
+ "walkdir",
+]
+
+[[package]]
+name = "rust-embed"
+version = "8.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b1e7d90385b59f0a6bf3d3b757f3ca4ece2048265d70db20a2016043d4509a40"
+dependencies = [
+ "rust-embed-impl 8.0.0",
+ "rust-embed-utils 8.0.0",
"walkdir",
]
@@ -2633,12 +2644,25 @@ checksum = "4d4e0f0ced47ded9a68374ac145edd65a6c1fa13a96447b873660b2a568a0fd7"
dependencies = [
"proc-macro2",
"quote",
- "rust-embed-utils",
+ "rust-embed-utils 7.5.0",
"shellexpand",
"syn 1.0.109",
"walkdir",
]
+[[package]]
+name = "rust-embed-impl"
+version = "8.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3c3d8c6fd84090ae348e63a84336b112b5c3918b3bf0493a581f7bd8ee623c29"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "rust-embed-utils 8.0.0",
+ "syn 2.0.28",
+ "walkdir",
+]
+
[[package]]
name = "rust-embed-utils"
version = "7.5.0"
@@ -2649,6 +2673,16 @@ dependencies = [
"walkdir",
]
+[[package]]
+name = "rust-embed-utils"
+version = "8.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "873feff8cb7bf86fdf0a71bb21c95159f4e4a37dd7a4bd1855a940909b583ada"
+dependencies = [
+ "sha2",
+ "walkdir",
+]
+
[[package]]
name = "rust-stemmers"
version = "1.2.0"
@@ -3047,7 +3081,7 @@ dependencies = [
"nvml-wrapper",
"opentelemetry",
"opentelemetry-otlp",
- "rust-embed",
+ "rust-embed 8.0.0",
"serde",
"serde_json",
"serdeconv",
@@ -4015,7 +4049,7 @@ dependencies = [
"axum",
"mime_guess",
"regex",
- "rust-embed",
+ "rust-embed 6.6.1",
"serde",
"serde_json",
"utoipa",
diff --git a/Makefile b/Makefile
index 30e9e41..87b4bce 100644
--- a/Makefile
+++ b/Makefile
@@ -6,3 +6,8 @@ loadtest:
fix:
cargo clippy --fix --allow-dirty --allow-staged && cargo +nightly fmt
+
+update-playground:
+ cd clients/tabby-playground && yarn build
+ rm -rf crates/tabby/playground && cp -R clients/tabby-playground/out crates/tabby/playground
+
diff --git a/clients/tabby-playground/.env.example b/clients/tabby-playground/.env.example
new file mode 100644
index 0000000..e0d09d0
--- /dev/null
+++ b/clients/tabby-playground/.env.example
@@ -0,0 +1 @@
+NEXT_PUBLIC_TABBY_SERVER_URL=http://127.0.0.1:8080
\ No newline at end of file
diff --git a/clients/tabby-playground/.eslintrc.json b/clients/tabby-playground/.eslintrc.json
new file mode 100644
index 0000000..6ec5479
--- /dev/null
+++ b/clients/tabby-playground/.eslintrc.json
@@ -0,0 +1,25 @@
+{
+ "$schema": "https://json.schemastore.org/eslintrc",
+ "root": true,
+ "extends": [
+ "next/core-web-vitals",
+ "prettier",
+ "plugin:tailwindcss/recommended"
+ ],
+ "plugins": ["tailwindcss"],
+ "rules": {
+ "tailwindcss/no-custom-classname": "off"
+ },
+ "settings": {
+ "tailwindcss": {
+ "callees": ["cn", "cva"],
+ "config": "tailwind.config.js"
+ }
+ },
+ "overrides": [
+ {
+ "files": ["*.ts", "*.tsx"],
+ "parser": "@typescript-eslint/parser"
+ }
+ ]
+}
diff --git a/clients/tabby-playground/.gitignore b/clients/tabby-playground/.gitignore
new file mode 100644
index 0000000..83d560e
--- /dev/null
+++ b/clients/tabby-playground/.gitignore
@@ -0,0 +1,38 @@
+# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
+
+# dependencies
+node_modules
+.pnp
+.pnp.js
+
+# testing
+coverage
+
+# next.js
+.next/
+out/
+build
+
+# misc
+.DS_Store
+*.pem
+
+# debug
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+.pnpm-debug.log*
+
+# local env files
+.env.local
+.env.development.local
+.env.test.local
+.env.production.local
+
+# turbo
+.turbo
+
+.contentlayer
+.env
+.vercel
+.vscode
\ No newline at end of file
diff --git a/clients/tabby-playground/LICENSE b/clients/tabby-playground/LICENSE
new file mode 100644
index 0000000..6c16c29
--- /dev/null
+++ b/clients/tabby-playground/LICENSE
@@ -0,0 +1,13 @@
+Copyright 2023 Vercel, Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
\ No newline at end of file
diff --git a/clients/tabby-playground/README.md b/clients/tabby-playground/README.md
new file mode 100644
index 0000000..14fa983
--- /dev/null
+++ b/clients/tabby-playground/README.md
@@ -0,0 +1,73 @@
+
+
+ Next.js AI Chatbot
+
+
+
+ An open-source AI chatbot app template built with Next.js, the Vercel AI SDK, OpenAI, and Vercel KV.
+
+
+
+ Features ·
+ Model Providers ·
+ Deploy Your Own ·
+ Running locally ·
+ Authors
+
+
+
+## Features
+
+- [Next.js](https://nextjs.org) App Router
+- React Server Components (RSCs), Suspense, and Server Actions
+- [Vercel AI SDK](https://sdk.vercel.ai/docs) for streaming chat UI
+- Support for OpenAI (default), Anthropic, Hugging Face, or custom AI chat models and/or LangChain
+- Edge runtime-ready
+- [shadcn/ui](https://ui.shadcn.com)
+ - Styling with [Tailwind CSS](https://tailwindcss.com)
+ - [Radix UI](https://radix-ui.com) for headless component primitives
+ - Icons from [Phosphor Icons](https://phosphoricons.com)
+- Chat History, rate limiting, and session storage with [Vercel KV](https://vercel.com/storage/kv)
+- [NextAuth.js](https://github.com/nextauthjs/next-auth) for authentication
+
+## Model Providers
+
+This template ships with OpenAI `gpt-3.5-turbo` as the default. However, thanks to the [Vercel AI SDK](https://sdk.vercel.ai/docs), you can switch LLM providers to [Anthropic](https://anthropic.com), [Hugging Face](https://huggingface.co), or using [LangChain](https://js.langchain.com) with just a few lines of code.
+
+## Deploy Your Own
+
+You can deploy your own version of the Next.js AI Chatbot to Vercel with one click:
+
+[](https://vercel.com/new/clone?demo-title=Next.js+Chat&demo-description=A+full-featured%2C+hackable+Next.js+AI+chatbot+built+by+Vercel+Labs&demo-url=https%3A%2F%2Fchat.vercel.ai%2F&demo-image=%2F%2Fimages.ctfassets.net%2Fe5382hct74si%2F4aVPvWuTmBvzM5cEdRdqeW%2F4234f9baf160f68ffb385a43c3527645%2FCleanShot_2023-06-16_at_17.09.21.png&project-name=Next.js+Chat&repository-name=nextjs-chat&repository-url=https%3A%2F%2Fgithub.com%2Fvercel-labs%2Fai-chatbot&from=templates&skippable-integrations=1&env=OPENAI_API_KEY%2CAUTH_GITHUB_ID%2CAUTH_GITHUB_SECRET%2CAUTH_SECRET&envDescription=How+to+get+these+env+vars&envLink=https%3A%2F%2Fgithub.com%2Fvercel-labs%2Fai-chatbot%2Fblob%2Fmain%2F.env.example&teamCreateStatus=hidden&stores=[{"type":"kv"}])
+
+## Creating a KV Database Instance
+
+Follow the steps outlined in the [quick start guide](https://vercel.com/docs/storage/vercel-kv/quickstart#create-a-kv-database) provided by Vercel. This guide will assist you in creating and configuring your KV database instance on Vercel, enabling your application to interact with it.
+
+Remember to update your environment variables (`KV_URL`, `KV_REST_API_URL`, `KV_REST_API_TOKEN`, `KV_REST_API_READ_ONLY_TOKEN`) in the `.env` file with the appropriate credentials provided during the KV database setup.
+
+
+## Running locally
+
+You will need to use the environment variables [defined in `.env.example`](.env.example) to run Next.js AI Chatbot. It's recommended you use [Vercel Environment Variables](https://vercel.com/docs/concepts/projects/environment-variables) for this, but a `.env` file is all that is necessary.
+
+> Note: You should not commit your `.env` file or it will expose secrets that will allow others to control access to your various OpenAI and authentication provider accounts.
+
+1. Install Vercel CLI: `npm i -g vercel`
+2. Link local instance with Vercel and GitHub accounts (creates `.vercel` directory): `vercel link`
+3. Download your environment variables: `vercel env pull`
+
+```bash
+pnpm install
+pnpm dev
+```
+
+Your app template should now be running on [localhost:3000](http://localhost:3000/).
+
+## Authors
+
+This library is created by [Vercel](https://vercel.com) and [Next.js](https://nextjs.org) team members, with contributions from:
+
+- Jared Palmer ([@jaredpalmer](https://twitter.com/jaredpalmer)) - [Vercel](https://vercel.com)
+- Shu Ding ([@shuding\_](https://twitter.com/shuding_)) - [Vercel](https://vercel.com)
+- shadcn ([@shadcn](https://twitter.com/shadcn)) - [Contractor](https://shadcn.com)
diff --git a/clients/tabby-playground/app/globals.css b/clients/tabby-playground/app/globals.css
new file mode 100644
index 0000000..9beeb2c
--- /dev/null
+++ b/clients/tabby-playground/app/globals.css
@@ -0,0 +1,78 @@
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
+
+@layer base {
+ :root {
+ --background: 0 0% 100%;
+ --foreground: 240 10% 3.9%;
+
+ --muted: 240 4.8% 95.9%;
+ --muted-foreground: 240 3.8% 46.1%;
+
+ --popover: 0 0% 100%;
+ --popover-foreground: 240 10% 3.9%;
+
+ --card: 0 0% 100%;
+ --card-foreground: 240 10% 3.9%;
+
+ --border: 240 5.9% 90%;
+ --input: 240 5.9% 90%;
+
+ --primary: 240 5.9% 10%;
+ --primary-foreground: 0 0% 98%;
+
+ --secondary: 240 4.8% 95.9%;
+ --secondary-foreground: 240 5.9% 10%;
+
+ --accent: 240 4.8% 95.9%;
+ --accent-foreground: ;
+
+ --destructive: 0 84.2% 60.2%;
+ --destructive-foreground: 0 0% 98%;
+
+ --ring: 240 5% 64.9%;
+
+ --radius: 0.5rem;
+ }
+
+ .dark {
+ --background: 240 10% 3.9%;
+ --foreground: 0 0% 98%;
+
+ --muted: 240 3.7% 15.9%;
+ --muted-foreground: 240 5% 64.9%;
+
+ --popover: 240 10% 3.9%;
+ --popover-foreground: 0 0% 98%;
+
+ --card: 240 10% 3.9%;
+ --card-foreground: 0 0% 98%;
+
+ --border: 240 3.7% 15.9%;
+ --input: 240 3.7% 15.9%;
+
+ --primary: 0 0% 98%;
+ --primary-foreground: 240 5.9% 10%;
+
+ --secondary: 240 3.7% 15.9%;
+ --secondary-foreground: 0 0% 98%;
+
+ --accent: 240 3.7% 15.9%;
+ --accent-foreground: ;
+
+ --destructive: 0 62.8% 30.6%;
+ --destructive-foreground: 0 85.7% 97.3%;
+
+ --ring: 240 3.7% 15.9%;
+ }
+}
+
+@layer base {
+ * {
+ @apply border-border;
+ }
+ body {
+ @apply bg-background text-foreground;
+ }
+}
diff --git a/clients/tabby-playground/app/layout.tsx b/clients/tabby-playground/app/layout.tsx
new file mode 100644
index 0000000..3d0d91e
--- /dev/null
+++ b/clients/tabby-playground/app/layout.tsx
@@ -0,0 +1,51 @@
+import { Metadata } from 'next'
+
+import { Toaster } from 'react-hot-toast'
+
+import '@/app/globals.css'
+import { fontMono, fontSans } from '@/lib/fonts'
+import { cn } from '@/lib/utils'
+import { TailwindIndicator } from '@/components/tailwind-indicator'
+import { Providers } from '@/components/providers'
+import { Header } from '@/components/header'
+
+export const metadata: Metadata = {
+ title: {
+ default: 'Tabby Playground',
+ template: `%s - Tabby Playground`
+ },
+ description: 'Tabby, an opensource, self-hosted AI coding assistant.',
+ themeColor: [
+ { media: '(prefers-color-scheme: light)', color: 'white' },
+ { media: '(prefers-color-scheme: dark)', color: 'black' }
+ ],
+}
+
+interface RootLayoutProps {
+ children: React.ReactNode
+}
+
+export default function RootLayout({ children }: RootLayoutProps) {
+ return (
+
+
+