├── .husky ├── .gitignore └── pre-commit ├── public ├── robots.txt ├── banner.png ├── social.png ├── favicon.ico ├── favicon-16x16.png ├── favicon-32x32.png ├── apple-touch-icon.png ├── android-chrome-192x192.png ├── android-chrome-512x512.png └── site.webmanifest ├── .github └── FUNDING.yml ├── .gitattributes ├── .dockerignore ├── postcss.config.cjs ├── prisma ├── useSqlite.sh └── schema.prisma ├── aws └── cf │ ├── deploy.sh │ └── agent.cf.json ├── prettier.config.cjs ├── src ├── pages │ ├── api │ │ ├── auth │ │ │ └── [...nextauth].ts │ │ ├── trpc │ │ │ └── [trpc].ts │ │ ├── execute.ts │ │ ├── chain.ts │ │ └── create.ts │ ├── _app.tsx │ └── index.tsx ├── server │ ├── db.ts │ ├── api │ │ ├── root.ts │ │ ├── routers │ │ │ ├── example.ts │ │ │ └── chain.ts │ │ └── trpc.ts │ └── auth.ts ├── components │ ├── DottedGridBackground.tsx │ ├── loader.tsx │ ├── Badge.tsx │ ├── motions │ │ ├── popin.tsx │ │ ├── FadeOut.tsx │ │ └── expand.tsx │ ├── Input.tsx │ ├── Button.tsx │ ├── HelpDialog.tsx │ ├── SettingsDialog.tsx │ ├── Dialog.tsx │ ├── toast.tsx │ ├── Drawer.tsx │ ├── AutonomousAgent.ts │ └── ChatWindow.tsx ├── env │ ├── server.mjs │ ├── client.mjs │ └── schema.mjs ├── styles │ └── globals.css ├── utils │ ├── api.ts │ └── chain.ts └── layout │ └── default.tsx ├── .env.example ├── tsconfig.json ├── tailwind.config.cjs ├── setup.sh ├── next.config.mjs ├── .gitignore ├── Dockerfile ├── .eslintrc.json ├── package.json ├── README.md └── LICENSE /.husky/.gitignore: -------------------------------------------------------------------------------- 1 | _ 2 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Allow: / -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: reworkd-admin 2 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /public/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kuilenren/AgentGPT/main/public/banner.png -------------------------------------------------------------------------------- /public/social.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kuilenren/AgentGPT/main/public/social.png -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npx lint-staged 5 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kuilenren/AgentGPT/main/public/favicon.ico -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | **/.git 2 | **/node_modules 3 | **/idea 4 | **/.next 5 | **/aws 6 | **/.husky 7 | **/venv -------------------------------------------------------------------------------- /public/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kuilenren/AgentGPT/main/public/favicon-16x16.png -------------------------------------------------------------------------------- /public/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kuilenren/AgentGPT/main/public/favicon-32x32.png -------------------------------------------------------------------------------- /public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kuilenren/AgentGPT/main/public/apple-touch-icon.png -------------------------------------------------------------------------------- /public/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kuilenren/AgentGPT/main/public/android-chrome-192x192.png -------------------------------------------------------------------------------- /public/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kuilenren/AgentGPT/main/public/android-chrome-512x512.png -------------------------------------------------------------------------------- /postcss.config.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /prisma/useSqlite.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | cd "$(dirname "$0")" 3 | 4 | sed -ie 's/postgresql/sqlite/g' schema.prisma 5 | sed -ie 's/@db.Text//' schema.prisma 6 | -------------------------------------------------------------------------------- /aws/cf/deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | cd "$(dirname "$0")" 3 | 4 | aws cloudformation create-stack --stack-name agent \ 5 | --template-body file:///$PWD/agent.cf.json -------------------------------------------------------------------------------- /prettier.config.cjs: -------------------------------------------------------------------------------- 1 | /** @type {import("prettier").Config} */ 2 | module.exports = { 3 | plugins: [require.resolve("prettier-plugin-tailwindcss")], 4 | }; 5 | -------------------------------------------------------------------------------- /src/pages/api/auth/[...nextauth].ts: -------------------------------------------------------------------------------- 1 | import NextAuth from "next-auth"; 2 | import { authOptions } from "../../../server/auth"; 3 | 4 | export default NextAuth(authOptions); 5 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | # Deployment Environment: 2 | NODE_ENV=development 3 | 4 | # Next Auth config: 5 | # Generate a secret with `openssl rand -base64 32` 6 | NEXTAUTH_SECRET=changeme 7 | NEXTAUTH_URL=http://localhost:3000 8 | 9 | # Prisma 10 | DATABASE_URL=file:./db.sqlite 11 | 12 | # External APIs: 13 | OPENAI_API_KEY=changeme 14 | -------------------------------------------------------------------------------- /public/site.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Agent-GPT", 3 | "short_name": "Agent-GPT", 4 | "icons": [ 5 | { 6 | "src": "/android-chrome-192x192.png", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | }, 10 | { 11 | "src": "/android-chrome-512x512.png", 12 | "sizes": "512x512", 13 | "type": "image/png" 14 | } 15 | ], 16 | "theme_color": "#ffffff", 17 | "background_color": "#ffffff", 18 | "display": "standalone" 19 | } 20 | -------------------------------------------------------------------------------- /src/server/db.ts: -------------------------------------------------------------------------------- 1 | import { PrismaClient } from "@prisma/client"; 2 | 3 | import { env } from "../env/server.mjs"; 4 | 5 | const globalForPrisma = globalThis as unknown as { prisma: PrismaClient }; 6 | 7 | export const prisma = 8 | globalForPrisma.prisma || 9 | new PrismaClient({ 10 | log: 11 | env.NODE_ENV === "development" ? ["query", "error", "warn"] : ["error"], 12 | }); 13 | 14 | if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = prisma; 15 | -------------------------------------------------------------------------------- /src/server/api/root.ts: -------------------------------------------------------------------------------- 1 | import { createTRPCRouter } from "./trpc"; 2 | import { exampleRouter } from "./routers/example"; 3 | import { chainRouter } from "./routers/chain"; 4 | 5 | /** 6 | * This is the primary router for your server. 7 | * 8 | * All routers added in /api/routers should be manually added here 9 | */ 10 | export const appRouter = createTRPCRouter({ 11 | example: exampleRouter, 12 | chain: chainRouter, 13 | }); 14 | 15 | // export type definition of API 16 | export type AppRouter = typeof appRouter; 17 | -------------------------------------------------------------------------------- /src/components/DottedGridBackground.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | interface DottedGridBackgroundProps { 4 | children: React.ReactNode; 5 | className?: string; 6 | } 7 | 8 | const DottedGridBackground = ({ 9 | children, 10 | className, 11 | }: DottedGridBackgroundProps) => { 12 | return ( 13 |
14 |
15 | {children} 16 |
17 | ); 18 | }; 19 | 20 | export default DottedGridBackground; 21 | -------------------------------------------------------------------------------- /src/server/api/routers/example.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | 3 | import { createTRPCRouter, publicProcedure, protectedProcedure } from "../trpc"; 4 | 5 | export const exampleRouter = createTRPCRouter({ 6 | hello: publicProcedure 7 | .input(z.object({ text: z.string() })) 8 | .query(({ input }) => { 9 | return { 10 | greeting: `Hello ${input.text}`, 11 | }; 12 | }), 13 | getSecretMessage: protectedProcedure.query(() => { 14 | return "you can now see this secret message!"; 15 | }), 16 | }); 17 | -------------------------------------------------------------------------------- /src/components/loader.tsx: -------------------------------------------------------------------------------- 1 | import { Ring } from "@uiball/loaders"; 2 | 3 | interface LoaderProps { 4 | className?: string; 5 | size?: number; 6 | speed?: number; 7 | lineWeight?: number; 8 | } 9 | 10 | const Loader: React.FC = ({ 11 | className, 12 | size = 16, 13 | speed = 2, 14 | lineWeight = 7, 15 | }) => { 16 | return ( 17 |
18 | 19 |
20 | ); 21 | }; 22 | 23 | export default Loader; 24 | -------------------------------------------------------------------------------- /src/components/Badge.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import clsx from "clsx"; 3 | 4 | interface BadgeProps { 5 | children: React.ReactNode; 6 | } 7 | 8 | const Badge = ({ children }: BadgeProps) => { 9 | return ( 10 |
17 | {children} 18 |
19 | ); 20 | }; 21 | 22 | export default Badge; 23 | -------------------------------------------------------------------------------- /src/server/api/routers/chain.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | 3 | import { createTRPCRouter, publicProcedure } from "../trpc"; 4 | import { startGoalAgent } from "../../../utils/chain"; 5 | 6 | export const chainRouter = createTRPCRouter({ 7 | startAgent: publicProcedure 8 | .input(z.object({ prompt: z.string() })) 9 | .mutation(async ({ input }) => { 10 | // const completion = (await startGoalAgent(input.prompt)) as { 11 | // text: string; 12 | // }; 13 | // 14 | // return { tasks: JSON.parse(completion.text) as string[] }; 15 | }), 16 | }); 17 | -------------------------------------------------------------------------------- /src/components/motions/popin.tsx: -------------------------------------------------------------------------------- 1 | import { motion } from "framer-motion"; 2 | import type { PropsWithChildren } from "react"; 3 | 4 | interface MotionProps extends PropsWithChildren { 5 | className?: string; 6 | delay?: number; 7 | } 8 | 9 | const PopIn = (props: MotionProps) => ( 10 | 16 | {props.children} 17 | 18 | ); 19 | 20 | PopIn.displayName = "PopIn"; 21 | export default PopIn; 22 | -------------------------------------------------------------------------------- /src/components/motions/FadeOut.tsx: -------------------------------------------------------------------------------- 1 | import { motion } from "framer-motion"; 2 | import type { PropsWithChildren } from "react"; 3 | 4 | interface MotionProps extends PropsWithChildren { 5 | className?: string; 6 | delay?: number; 7 | } 8 | 9 | const FadeOut = (props: MotionProps) => ( 10 | 16 | {props.children} 17 | 18 | ); 19 | 20 | FadeOut.displayName = "FadeOut"; 21 | export default FadeOut; 22 | -------------------------------------------------------------------------------- /src/pages/_app.tsx: -------------------------------------------------------------------------------- 1 | import { type AppType } from "next/app"; 2 | import { type Session } from "next-auth"; 3 | import { SessionProvider } from "next-auth/react"; 4 | 5 | import { api } from "../utils/api"; 6 | 7 | import "../styles/globals.css"; 8 | import { Analytics } from "@vercel/analytics/react"; 9 | 10 | const MyApp: AppType<{ session: Session | null }> = ({ 11 | Component, 12 | pageProps: { session, ...pageProps }, 13 | }) => { 14 | return ( 15 | 16 | 17 | 18 | 19 | ); 20 | }; 21 | 22 | export default api.withTRPC(MyApp); 23 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2017", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "noEmit": true, 10 | "esModuleInterop": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "jsx": "preserve", 16 | "incremental": true, 17 | "noUncheckedIndexedAccess": true 18 | }, 19 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "**/*.cjs", "**/*.mjs"], 20 | "exclude": ["node_modules"] 21 | } 22 | -------------------------------------------------------------------------------- /src/pages/api/trpc/[trpc].ts: -------------------------------------------------------------------------------- 1 | import { createNextApiHandler } from "@trpc/server/adapters/next"; 2 | 3 | import { env } from "../../../env/server.mjs"; 4 | import { createTRPCContext } from "../../../server/api/trpc"; 5 | import { appRouter } from "../../../server/api/root"; 6 | 7 | // export API handler 8 | export default createNextApiHandler({ 9 | router: appRouter, 10 | createContext: createTRPCContext, 11 | onError: 12 | env.NODE_ENV === "development" 13 | ? ({ path, error }) => { 14 | console.error( 15 | `❌ tRPC failed on ${path ?? ""}: ${error.message}`, 16 | ); 17 | } 18 | : undefined, 19 | }); 20 | -------------------------------------------------------------------------------- /tailwind.config.cjs: -------------------------------------------------------------------------------- 1 | /** @type {import("tailwindcss").Config} */ 2 | const defaultTheme = require("tailwindcss/defaultTheme"); 3 | 4 | module.exports = { 5 | content: ["./src/**/*.{js,ts,jsx,tsx}"], 6 | theme: { 7 | screens: { 8 | "xs": "300px", 9 | 10 | "sm-h": { "raw": "(min-height: 700px)" }, 11 | "md-h": { "raw": "(min-height: 800px)" }, 12 | "lg-h": { "raw": "(min-height: 1000px)" }, 13 | 14 | ...defaultTheme.screens 15 | }, 16 | extend: { 17 | boxShadow: { 18 | "3xl": "0 40px 70px -15px rgba(0, 0, 0, 0.40)" // Customize the shadow value according to your preferences. 19 | } 20 | } 21 | }, 22 | plugins: [] 23 | }; 24 | -------------------------------------------------------------------------------- /setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | cd "$(dirname "$0")" || exit 3 | 4 | echo -n "Enter your OpenAI Key (eg: sk...): " 5 | read OPENAI_API_KEY 6 | 7 | NEXTAUTH_SECRET=$(openssl rand -base64 32) 8 | 9 | ENV="NODE_ENV=development\n\ 10 | NEXTAUTH_SECRET=$NEXTAUTH_SECRET\n\ 11 | NEXTAUTH_URL=http://localhost:3000\n\ 12 | OPENAI_API_KEY=$OPENAI_API_KEY\n\ 13 | DATABASE_URL=file:../db/db.sqlite\n" 14 | 15 | printf $ENV > .env 16 | 17 | if [ "$1" = "--docker" ]; then 18 | printf $ENV > .env.docker 19 | docker build -t agentgpt . 20 | docker run -d --name agentgpt -p 3000:3000 -v $(pwd)/db:/app/db agentgpt 21 | else 22 | printf $ENV > .env 23 | ./prisma/useSqlite.sh 24 | npm install 25 | npm run dev 26 | fi -------------------------------------------------------------------------------- /src/components/motions/expand.tsx: -------------------------------------------------------------------------------- 1 | import { motion } from "framer-motion"; 2 | import type { PropsWithChildren } from "react"; 3 | 4 | interface MotionProps extends PropsWithChildren { 5 | className?: string; 6 | delay?: number; 7 | type?: "spring" | "tween"; 8 | } 9 | 10 | const Expand = (props: MotionProps) => ( 11 | 21 | {props.children} 22 | 23 | ); 24 | 25 | Expand.displayName = "Expand"; 26 | export default Expand; 27 | -------------------------------------------------------------------------------- /next.config.mjs: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | /** 3 | * Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation. 4 | * This is especially useful for Docker builds. 5 | */ 6 | !process.env.SKIP_ENV_VALIDATION && (await import("./src/env/server.mjs")); 7 | 8 | /** @type {import("next").NextConfig} */ 9 | const config = { 10 | reactStrictMode: true, 11 | /* If trying out the experimental appDir, comment the i18n config out 12 | * @see https://github.com/vercel/next.js/issues/41980 */ 13 | i18n: { 14 | locales: ["en"], 15 | defaultLocale: "en", 16 | }, 17 | webpack: function (config, options) { 18 | config.experiments = { asyncWebAssembly: true, layers: true }; 19 | return config; 20 | } 21 | }; 22 | export default config; 23 | -------------------------------------------------------------------------------- /.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.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # database 12 | /prisma/db.sqlite 13 | /prisma/db.sqlite-journal 14 | /db/db.sqlite 15 | 16 | # next.js 17 | /.next/ 18 | /out/ 19 | next-env.d.ts 20 | 21 | # production 22 | /build 23 | 24 | # misc 25 | .DS_Store 26 | *.pem 27 | 28 | # debug 29 | npm-debug.log* 30 | yarn-debug.log* 31 | yarn-error.log* 32 | .pnpm-debug.log* 33 | 34 | # local env files 35 | # do not commit any .env files to git, except for the .env.example file. https://create.t3.gg/en/usage/env-variables#using-environment-variables 36 | .env* 37 | 38 | # vercel 39 | .vercel 40 | 41 | # typescript 42 | *.tsbuildinfo 43 | .idea 44 | -------------------------------------------------------------------------------- /src/pages/api/execute.ts: -------------------------------------------------------------------------------- 1 | import { createModel, executeTaskAgent } from "../../utils/chain"; 2 | import type { NextRequest } from "next/server"; 3 | import { NextResponse } from "next/server"; 4 | 5 | interface RequestBody { 6 | customApiKey: string; 7 | goal: string; 8 | task: string; 9 | } 10 | export const config = { 11 | runtime: "edge", 12 | }; 13 | 14 | export default async (request: NextRequest) => { 15 | let data: RequestBody | null = null; 16 | try { 17 | data = (await request.json()) as RequestBody; 18 | const completion = await executeTaskAgent( 19 | createModel(data.customApiKey), 20 | data.goal, 21 | data.task 22 | ); 23 | 24 | return NextResponse.json({ 25 | response: completion.text as string, 26 | }); 27 | } catch (e) {} 28 | 29 | return NextResponse.error(); 30 | }; 31 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Use the official Node.js image as the base image 2 | FROM node:19-alpine 3 | 4 | # Set the working directory 5 | WORKDIR /app 6 | 7 | # Copy package.json and package-lock.json to the working directory 8 | COPY package*.json ./ 9 | 10 | # Install dependencies 11 | RUN npm ci 12 | 13 | # Copy the rest of the application code 14 | COPY . . 15 | RUN mv .env.docker .env \ 16 | && sed -ie 's/postgresql/sqlite/g' prisma/schema.prisma \ 17 | && sed -ie 's/@db.Text//' prisma/schema.prisma 18 | 19 | # Expose the port the app will run on 20 | EXPOSE 3000 21 | 22 | # Add Prisma and generate Prisma client 23 | RUN npx prisma generate \ 24 | && npx prisma migrate dev --name init \ 25 | && npx prisma db push 26 | 27 | # Build the Next.js app 28 | RUN npm run build 29 | 30 | 31 | # Start the application 32 | CMD ["npm", "start"] 33 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "overrides": [ 3 | { 4 | "extends": [ 5 | "plugin:@typescript-eslint/recommended-requiring-type-checking" 6 | ], 7 | "files": ["*.ts", "*.tsx"], 8 | "parserOptions": { 9 | "project": "tsconfig.json" 10 | } 11 | } 12 | ], 13 | "parser": "@typescript-eslint/parser", 14 | "parserOptions": { 15 | "project": "./tsconfig.json" 16 | }, 17 | "plugins": ["@typescript-eslint"], 18 | "extends": ["next/core-web-vitals", "plugin:@typescript-eslint/recommended"], 19 | "rules": { 20 | "@typescript-eslint/consistent-type-imports": "warn", 21 | "@typescript-eslint/no-unused-vars": "off", 22 | "@typescript-eslint/no-unsafe-return": "off", 23 | "@typescript-eslint/no-unsafe-member-access": "off", 24 | "@typescript-eslint/no-unsafe-call": "off", 25 | "@typescript-eslint/no-unsafe-assignment": "off" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/pages/api/chain.ts: -------------------------------------------------------------------------------- 1 | import { 2 | createModel, 3 | extractArray, 4 | realTasksFilter, 5 | startGoalAgent, 6 | } from "../../utils/chain"; 7 | import type { NextRequest } from "next/server"; 8 | import { NextResponse } from "next/server"; 9 | 10 | export const config = { 11 | runtime: "edge", 12 | }; 13 | 14 | interface RequestBody { 15 | customApiKey: string; 16 | goal: string; 17 | } 18 | 19 | export default async (request: NextRequest) => { 20 | let data: RequestBody | null = null; 21 | try { 22 | data = (await request.json()) as RequestBody; 23 | const completion = await startGoalAgent( 24 | createModel(data.customApiKey), 25 | data.goal 26 | ); 27 | 28 | const tasks = extractArray(completion.text as string).filter( 29 | realTasksFilter 30 | ); 31 | return NextResponse.json({ tasks }); 32 | } catch (e) {} 33 | 34 | return NextResponse.error(); 35 | }; 36 | -------------------------------------------------------------------------------- /src/env/server.mjs: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | /** 3 | * This file is included in `/next.config.mjs` which ensures the app isn't built with invalid env vars. 4 | * It has to be a `.mjs`-file to be imported there. 5 | */ 6 | import { serverSchema, serverEnv } from "./schema.mjs"; 7 | import { env as clientEnv, formatErrors } from "./client.mjs"; 8 | 9 | const _serverEnv = serverSchema.safeParse(serverEnv); 10 | 11 | if (!_serverEnv.success) { 12 | console.error( 13 | "❌ Invalid environment variables:\n", 14 | ...formatErrors(_serverEnv.error.format()), 15 | ); 16 | throw new Error("Invalid environment variables"); 17 | } 18 | 19 | for (let key of Object.keys(_serverEnv.data)) { 20 | if (key.startsWith("NEXT_PUBLIC_")) { 21 | console.warn("❌ You are exposing a server-side env-variable:", key); 22 | 23 | throw new Error("You are exposing a server-side env-variable"); 24 | } 25 | } 26 | 27 | export const env = { ..._serverEnv.data, ...clientEnv }; 28 | -------------------------------------------------------------------------------- /src/pages/api/create.ts: -------------------------------------------------------------------------------- 1 | import { 2 | createModel, 3 | executeCreateTaskAgent, 4 | extractArray, 5 | realTasksFilter, 6 | } from "../../utils/chain"; 7 | import type { NextRequest } from "next/server"; 8 | import { NextResponse } from "next/server"; 9 | 10 | export const config = { 11 | runtime: "edge", 12 | }; 13 | 14 | interface RequestBody { 15 | customApiKey: string; 16 | goal: string; 17 | tasks: string[]; 18 | lastTask: string; 19 | result: string; 20 | } 21 | 22 | export default async (request: NextRequest) => { 23 | let data: RequestBody | null = null; 24 | try { 25 | data = (await request.json()) as RequestBody; 26 | const completion = await executeCreateTaskAgent( 27 | createModel(data.customApiKey), 28 | data.goal, 29 | data.tasks, 30 | data.lastTask, 31 | data.result 32 | ); 33 | 34 | const tasks = extractArray(completion.text as string).filter( 35 | realTasksFilter 36 | ); 37 | return NextResponse.json({ tasks }); 38 | } catch (e) {} 39 | 40 | return NextResponse.error(); 41 | }; 42 | -------------------------------------------------------------------------------- /src/env/client.mjs: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | import { clientEnv, clientSchema } from "./schema.mjs"; 3 | 4 | const _clientEnv = clientSchema.safeParse(clientEnv); 5 | 6 | export const formatErrors = ( 7 | /** @type {import('zod').ZodFormattedError,string>} */ 8 | errors, 9 | ) => 10 | Object.entries(errors) 11 | .map(([name, value]) => { 12 | if (value && "_errors" in value) 13 | return `${name}: ${value._errors.join(", ")}\n`; 14 | }) 15 | .filter(Boolean); 16 | 17 | if (!_clientEnv.success) { 18 | console.error( 19 | "❌ Invalid environment variables:\n", 20 | ...formatErrors(_clientEnv.error.format()), 21 | ); 22 | throw new Error("Invalid environment variables"); 23 | } 24 | 25 | for (let key of Object.keys(_clientEnv.data)) { 26 | if (!key.startsWith("NEXT_PUBLIC_")) { 27 | console.warn( 28 | `❌ Invalid public environment variable name: ${key}. It must begin with 'NEXT_PUBLIC_'`, 29 | ); 30 | 31 | throw new Error("Invalid public environment variable name"); 32 | } 33 | } 34 | 35 | export const env = _clientEnv.data; 36 | -------------------------------------------------------------------------------- /src/components/Input.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import clsx from "clsx"; 3 | 4 | interface InputProps { 5 | left?: React.ReactNode; 6 | value: string; 7 | onChange: (e: React.ChangeEvent) => void; 8 | placeholder?: string; 9 | disabled?: boolean; 10 | } 11 | 12 | const Input = ({ 13 | placeholder, 14 | left, 15 | value, 16 | onChange, 17 | disabled, 18 | }: InputProps) => { 19 | return ( 20 |
21 | {left && ( 22 |
23 | {left} 24 |
25 | )} 26 | 38 |
39 | ); 40 | }; 41 | 42 | export default Input; 43 | -------------------------------------------------------------------------------- /prisma/schema.prisma: -------------------------------------------------------------------------------- 1 | generator client { 2 | provider = "prisma-client-js" 3 | } 4 | 5 | datasource db { 6 | provider = "sqlite" 7 | url = env("DATABASE_URL") 8 | } 9 | 10 | model Example { 11 | id String @id @default(cuid()) 12 | createdAt DateTime @default(now()) 13 | updatedAt DateTime @updatedAt 14 | } 15 | 16 | // Necessary for Next auth 17 | model Account { 18 | id String @id @default(cuid()) 19 | userId String 20 | type String 21 | provider String 22 | providerAccountId String 23 | refresh_token String? 24 | access_token String? 25 | expires_at Int? 26 | token_type String? 27 | scope String? 28 | id_token String? 29 | session_state String? 30 | user User @relation(fields: [userId], references: [id], onDelete: Cascade) 31 | 32 | @@unique([provider, providerAccountId]) 33 | } 34 | 35 | model Session { 36 | id String @id @default(cuid()) 37 | sessionToken String @unique 38 | userId String 39 | expires DateTime 40 | user User @relation(fields: [userId], references: [id], onDelete: Cascade) 41 | } 42 | 43 | model User { 44 | id String @id @default(cuid()) 45 | name String? 46 | email String? @unique 47 | emailVerified DateTime? 48 | image String? 49 | accounts Account[] 50 | sessions Session[] 51 | } 52 | 53 | model VerificationToken { 54 | identifier String 55 | token String @unique 56 | expires DateTime 57 | 58 | @@unique([identifier, token]) 59 | } 60 | -------------------------------------------------------------------------------- /src/styles/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | /* Used for the background effect in the landing page */ 6 | .background { 7 | background-image: radial-gradient( 8 | circle, 9 | rgba(58, 58, 58, 0.75) 2px, 10 | transparent 0px 11 | ); 12 | background-size: 30px 30px; 13 | background-position: 0 0, 15px 15px; 14 | } 15 | 16 | .lower-gradient { 17 | background-image: linear-gradient( 18 | to top, 19 | rgba(255, 255, 255, 0.03), 20 | rgba(255, 255, 255, 0) 21 | ); 22 | height: 20vh; 23 | position: absolute; 24 | bottom: 0; 25 | left: 0; 26 | right: 0; 27 | } 28 | 29 | /* Used for code / table formatting within messages */ 30 | pre { 31 | @apply overflow-auto rounded-lg; 32 | } 33 | 34 | table { 35 | @apply w-full rounded-lg text-white; 36 | background-color: #0d1117; 37 | } 38 | 39 | th, 40 | td { 41 | @apply rounded-lg border border-gray-700 px-4 py-2; 42 | } 43 | 44 | th { 45 | background-color: #161b22; 46 | } 47 | 48 | tr:nth-child(even) { 49 | background-color: #1c2028; 50 | } 51 | 52 | /* Customize website's scrollbar like Mac OS 53 | Not supports in Firefox and IE */ 54 | /* total width */ 55 | div::-webkit-scrollbar { 56 | border-radius: 16px; 57 | background-color: #464649; 58 | width: 16px; 59 | } 60 | 61 | /* background of the scrollbar except button or resizer */ 62 | div::-webkit-scrollbar-track { 63 | border-radius: 16px; 64 | background-color: #464649; 65 | } 66 | 67 | /* scrollbar itself */ 68 | div::-webkit-scrollbar-thumb { 69 | background-color: #babac0; 70 | border-radius: 16px; 71 | border: 2px solid #464649; 72 | } 73 | 74 | /* set button(top and bottom of the scrollbar) */ 75 | div::-webkit-scrollbar-button { 76 | display: none; 77 | } 78 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "agent-gpt", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "build": "next build --no-lint", 7 | "dev": "next dev", 8 | "postinstall": "prisma generate", 9 | "lint": "next lint", 10 | "start": "next start", 11 | "prepare": "husky install" 12 | }, 13 | "dependencies": { 14 | "@formkit/auto-animate": "^1.0.0-beta.6", 15 | "@next-auth/prisma-adapter": "^1.0.5", 16 | "@prisma/client": "^4.9.0", 17 | "@radix-ui/react-toast": "^1.1.3", 18 | "@tanstack/react-query": "^4.20.0", 19 | "@trpc/client": "^10.9.0", 20 | "@trpc/next": "^10.9.0", 21 | "@trpc/react-query": "^10.9.0", 22 | "@trpc/server": "^10.9.0", 23 | "@uiball/loaders": "^1.2.6", 24 | "@vercel/analytics": "^0.1.11", 25 | "axios": "^1.3.5", 26 | "clsx": "^1.2.1", 27 | "framer-motion": "^10.11.2", 28 | "html-to-image": "^1.11.11", 29 | "langchain": "^0.0.53", 30 | "next": "13.1.6", 31 | "next-auth": "^4.19.0", 32 | "react": "18.2.0", 33 | "react-dom": "18.2.0", 34 | "react-icons": "^4.8.0", 35 | "react-markdown": "^8.0.7", 36 | "rehype-highlight": "^6.0.0", 37 | "remark-gfm": "^3.0.1", 38 | "superjson": "1.9.1", 39 | "zod": "^3.20.2" 40 | }, 41 | "devDependencies": { 42 | "@types/node": "^18.11.18", 43 | "@types/prettier": "^2.7.2", 44 | "@types/react": "^18.0.26", 45 | "@types/react-dom": "^18.0.10", 46 | "@typescript-eslint/eslint-plugin": "^5.47.1", 47 | "@typescript-eslint/parser": "^5.47.1", 48 | "autoprefixer": "^10.4.7", 49 | "eslint": "^8.30.0", 50 | "eslint-config-next": "13.1.6", 51 | "husky": "^8.0.3", 52 | "lint-staged": "^13.2.1", 53 | "postcss": "^8.4.14", 54 | "prettier": "^2.8.1", 55 | "prettier-plugin-tailwindcss": "^0.2.1", 56 | "prisma": "^4.9.0", 57 | "tailwindcss": "^3.2.0", 58 | "typescript": "^4.9.4" 59 | }, 60 | "ct3aMetadata": { 61 | "initVersion": "7.4.0" 62 | }, 63 | "lint-staged": { 64 | "*.js": "eslint --cache --fix", 65 | "*.{js,css,md}": "prettier --write" 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/components/Button.tsx: -------------------------------------------------------------------------------- 1 | import type { ForwardedRef } from "react"; 2 | import React, { forwardRef, useState } from "react"; 3 | import Loader from "./loader"; 4 | import clsx from "clsx"; 5 | 6 | export interface ButtonProps { 7 | type?: "button" | "submit" | "reset"; 8 | className?: string; 9 | icon?: React.ReactNode; 10 | children?: React.ReactNode; 11 | loader?: boolean; 12 | disabled?: boolean; 13 | enabledClassName?: string; 14 | onClick?: (e: React.MouseEvent) => Promise | void; 15 | } 16 | 17 | const Button = forwardRef( 18 | (props: ButtonProps, ref: ForwardedRef) => { 19 | const [loading, setLoading] = useState(false); 20 | const onClick = (e: React.MouseEvent) => { 21 | if (props.loader == true) setLoading(true); 22 | 23 | try { 24 | void Promise.resolve(props.onClick?.(e)).then(); 25 | } catch (e) { 26 | setLoading(false); 27 | } 28 | }; 29 | 30 | return ( 31 | 57 | ); 58 | } 59 | ); 60 | 61 | Button.displayName = "Button"; 62 | export default Button; 63 | -------------------------------------------------------------------------------- /src/env/schema.mjs: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | import { z } from "zod"; 3 | 4 | const requiredForProduction = () => process.env.NODE_ENV === "production" 5 | ? z.string().min(1).trim() 6 | : z.string().min(1).trim().optional() 7 | 8 | /** 9 | * Specify your server-side environment variables schema here. 10 | * This way you can ensure the app isn't built with invalid env vars. 11 | */ 12 | export const serverSchema = z.object({ 13 | DATABASE_URL: z.string().url(), 14 | NODE_ENV: z.enum(["development", "test", "production"]), 15 | NEXTAUTH_SECRET: requiredForProduction(), 16 | NEXTAUTH_URL: z.preprocess( 17 | // This makes Vercel deployments not fail if you don't set NEXTAUTH_URL 18 | // Since NextAuth.js automatically uses the VERCEL_URL if present. 19 | (str) => process.env.VERCEL_URL ?? str, 20 | // VERCEL_URL doesn't include `https` so it cant be validated as a URL 21 | process.env.VERCEL ? z.string() : z.string().url(), 22 | ), 23 | OPENAI_API_KEY: z.string() 24 | }); 25 | 26 | /** 27 | * You can't destruct `process.env` as a regular object in the Next.js 28 | * middleware, so you have to do it manually here. 29 | * @type {{ [k in keyof z.input]: string | undefined }} 30 | */ 31 | export const serverEnv = { 32 | DATABASE_URL: process.env.DATABASE_URL, 33 | NODE_ENV: process.env.NODE_ENV, 34 | NEXTAUTH_SECRET: process.env.NEXTAUTH_SECRET, 35 | NEXTAUTH_URL: process.env.NEXTAUTH_URL, 36 | OPENAI_API_KEY: process.env.OPENAI_API_KEY, 37 | }; 38 | 39 | /** 40 | * Specify your client-side environment variables schema here. 41 | * This way you can ensure the app isn't built with invalid env vars. 42 | * To expose them to the client, prefix them with `NEXT_PUBLIC_`. 43 | */ 44 | export const clientSchema = z.object({ 45 | // NEXT_PUBLIC_CLIENTVAR: z.string(), 46 | }); 47 | 48 | /** 49 | * You can't destruct `process.env` as a regular object, so you have to do 50 | * it manually here. This is because Next.js evaluates this at build time, 51 | * and only used environment variables are included in the build. 52 | * @type {{ [k in keyof z.input]: string | undefined }} 53 | */ 54 | export const clientEnv = { 55 | // NEXT_PUBLIC_CLIENTVAR: process.env.NEXT_PUBLIC_CLIENTVAR, 56 | }; 57 | -------------------------------------------------------------------------------- /src/server/auth.ts: -------------------------------------------------------------------------------- 1 | import type { GetServerSidePropsContext } from "next"; 2 | import { 3 | getServerSession, 4 | type NextAuthOptions, 5 | type DefaultSession, 6 | } from "next-auth"; 7 | import { PrismaAdapter } from "@next-auth/prisma-adapter"; 8 | import { prisma } from "./db"; 9 | 10 | /** 11 | * Module augmentation for `next-auth` types 12 | * Allows us to add custom properties to the `session` object 13 | * and keep type safety 14 | * @see https://next-auth.js.org/getting-started/typescript#module-augmentation 15 | **/ 16 | declare module "next-auth" { 17 | interface Session extends DefaultSession { 18 | user: { 19 | id: string; 20 | // ...other properties 21 | // role: UserRole; 22 | } & DefaultSession["user"]; 23 | } 24 | 25 | // interface User { 26 | // // ...other properties 27 | // // role: UserRole; 28 | // } 29 | } 30 | 31 | /** 32 | * Options for NextAuth.js used to configure 33 | * adapters, providers, callbacks, etc. 34 | * @see https://next-auth.js.org/configuration/options 35 | **/ 36 | export const authOptions: NextAuthOptions = { 37 | callbacks: { 38 | session({ session, user }) { 39 | if (session.user) { 40 | session.user.id = user.id; 41 | // session.user.role = user.role; <-- put other properties on the session here 42 | } 43 | return session; 44 | }, 45 | }, 46 | adapter: PrismaAdapter(prisma), 47 | providers: [ 48 | /** 49 | * ...add more providers here 50 | * 51 | * Most other providers require a bit more work than the Discord provider. 52 | * For example, the GitHub provider requires you to add the 53 | * `refresh_token_expires_in` field to the Account model. Refer to the 54 | * NextAuth.js docs for the provider you want to use. Example: 55 | * @see https://next-auth.js.org/providers/github 56 | **/ 57 | ], 58 | }; 59 | 60 | /** 61 | * Wrapper for getServerSession so that you don't need 62 | * to import the authOptions in every file. 63 | * @see https://next-auth.js.org/configuration/nextjs 64 | **/ 65 | export const getServerAuthSession = (ctx: { 66 | req: GetServerSidePropsContext["req"]; 67 | res: GetServerSidePropsContext["res"]; 68 | }) => { 69 | return getServerSession(ctx.req, ctx.res, authOptions); 70 | }; 71 | -------------------------------------------------------------------------------- /src/utils/api.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This is the client-side entrypoint for your tRPC API. 3 | * It's used to create the `api` object which contains the Next.js App-wrapper 4 | * as well as your typesafe react-query hooks. 5 | * 6 | * We also create a few inference helpers for input and output types 7 | */ 8 | import { httpBatchLink, loggerLink } from "@trpc/client"; 9 | import { createTRPCNext } from "@trpc/next"; 10 | import { type inferRouterInputs, type inferRouterOutputs } from "@trpc/server"; 11 | import superjson from "superjson"; 12 | 13 | import { type AppRouter } from "../server/api/root"; 14 | 15 | const getBaseUrl = () => { 16 | if (typeof window !== "undefined") return ""; // browser should use relative url 17 | if (process.env.VERCEL_URL) return `https://${process.env.VERCEL_URL}`; // SSR should use vercel url 18 | return `http://localhost:${process.env.PORT ?? 3000}`; // dev SSR should use localhost 19 | }; 20 | 21 | /** 22 | * A set of typesafe react-query hooks for your tRPC API 23 | */ 24 | export const api = createTRPCNext({ 25 | config() { 26 | return { 27 | /** 28 | * Transformer used for data de-serialization from the server 29 | * @see https://trpc.io/docs/data-transformers 30 | **/ 31 | transformer: superjson, 32 | 33 | /** 34 | * Links used to determine request flow from client to server 35 | * @see https://trpc.io/docs/links 36 | * */ 37 | links: [ 38 | loggerLink({ 39 | enabled: (opts) => 40 | process.env.NODE_ENV === "development" || 41 | (opts.direction === "down" && opts.result instanceof Error), 42 | }), 43 | httpBatchLink({ 44 | url: `${getBaseUrl()}/api/trpc`, 45 | }), 46 | ], 47 | }; 48 | }, 49 | /** 50 | * Whether tRPC should await queries when server rendering pages 51 | * @see https://trpc.io/docs/nextjs#ssr-boolean-default-false 52 | */ 53 | ssr: false, 54 | }); 55 | 56 | /** 57 | * Inference helper for inputs 58 | * @example type HelloInput = RouterInputs['example']['hello'] 59 | **/ 60 | export type RouterInputs = inferRouterInputs; 61 | /** 62 | * Inference helper for outputs 63 | * @example type HelloOutput = RouterOutputs['example']['hello'] 64 | **/ 65 | export type RouterOutputs = inferRouterOutputs; 66 | -------------------------------------------------------------------------------- /src/layout/default.tsx: -------------------------------------------------------------------------------- 1 | import { type ReactNode } from "react"; 2 | import Head from "next/head"; 3 | import DottedGridBackground from "../components/DottedGridBackground"; 4 | import Script from "next/script"; 5 | 6 | interface LayoutProps { 7 | children: ReactNode; 8 | } 9 | 10 | const DefaultLayout = (props: LayoutProps) => { 11 | const description = 12 | "Assemble, configure, and deploy autonomous AI Agents in your browser."; 13 | return ( 14 |
15 | 16 | AgentGPT 17 | 18 | 19 | 20 | 21 | 22 | 26 | 27 | 28 | 32 | 36 | 37 | 41 | 42 | 43 | 44 | 48 | 49 |