├── src
├── toolkits
│ ├── toolkits
│ │ ├── toolkit-types.ts
│ │ ├── e2b
│ │ │ ├── tools
│ │ │ │ ├── tools.ts
│ │ │ │ └── run_code
│ │ │ │ │ └── base.ts
│ │ │ ├── base.ts
│ │ │ ├── server.ts
│ │ │ └── client.tsx
│ │ ├── image
│ │ │ ├── tools
│ │ │ │ ├── tools.ts
│ │ │ │ └── generate
│ │ │ │ │ ├── base.ts
│ │ │ │ │ └── client.tsx
│ │ │ ├── base.ts
│ │ │ ├── client.tsx
│ │ │ └── server.ts
│ │ ├── notion
│ │ │ ├── components
│ │ │ │ ├── index.ts
│ │ │ │ └── tool-call-display.tsx
│ │ │ ├── tools
│ │ │ │ ├── client.ts
│ │ │ │ ├── server.ts
│ │ │ │ ├── index.ts
│ │ │ │ └── users
│ │ │ │ │ ├── base.ts
│ │ │ │ │ └── server.ts
│ │ │ ├── lib
│ │ │ │ └── title.ts
│ │ │ └── base.ts
│ │ ├── etsy
│ │ │ ├── tools
│ │ │ │ ├── tools.ts
│ │ │ │ └── get-listings
│ │ │ │ │ ├── base.ts
│ │ │ │ │ └── client.tsx
│ │ │ ├── base.ts
│ │ │ └── client.tsx
│ │ ├── github
│ │ │ ├── tools
│ │ │ │ ├── client.ts
│ │ │ │ ├── server.ts
│ │ │ │ └── index.ts
│ │ │ ├── lib
│ │ │ │ └── prs.ts
│ │ │ ├── base.ts
│ │ │ └── components
│ │ │ │ └── user-avatar.tsx
│ │ ├── twitter
│ │ │ ├── tools
│ │ │ │ ├── client.ts
│ │ │ │ ├── server.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── profile
│ │ │ │ │ ├── base.ts
│ │ │ │ │ └── server.ts
│ │ │ │ └── tweets
│ │ │ │ │ └── base.ts
│ │ │ └── base.ts
│ │ ├── discord
│ │ │ ├── tools
│ │ │ │ ├── client.ts
│ │ │ │ ├── server.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── get-user-info
│ │ │ │ │ ├── base.ts
│ │ │ │ │ └── server.ts
│ │ │ │ └── list-servers
│ │ │ │ │ ├── base.ts
│ │ │ │ │ └── server.ts
│ │ │ └── base.ts
│ │ ├── mem0
│ │ │ ├── tools
│ │ │ │ ├── tools.ts
│ │ │ │ ├── add_memory
│ │ │ │ │ └── base.ts
│ │ │ │ └── search_memories
│ │ │ │ │ └── base.ts
│ │ │ ├── base.ts
│ │ │ └── components
│ │ │ │ └── tool-call-display.tsx
│ │ ├── video
│ │ │ ├── tools
│ │ │ │ ├── index.ts
│ │ │ │ └── generate
│ │ │ │ │ ├── base.ts
│ │ │ │ │ └── client.tsx
│ │ │ ├── server.ts
│ │ │ ├── base.ts
│ │ │ ├── client.tsx
│ │ │ └── env-vars.tsx
│ │ ├── google-drive
│ │ │ ├── tools
│ │ │ │ ├── client.ts
│ │ │ │ ├── server.ts
│ │ │ │ ├── index.ts
│ │ │ │ └── read-file
│ │ │ │ │ └── base.ts
│ │ │ ├── base.ts
│ │ │ └── components
│ │ │ │ └── tool-call.tsx
│ │ ├── exa
│ │ │ ├── components
│ │ │ │ ├── index.ts
│ │ │ │ ├── tool-call-display.tsx
│ │ │ │ └── results-list.tsx
│ │ │ └── tools
│ │ │ │ ├── tools.ts
│ │ │ │ ├── crawling
│ │ │ │ ├── base.ts
│ │ │ │ ├── client.tsx
│ │ │ │ └── server.ts
│ │ │ │ ├── search
│ │ │ │ ├── base.ts
│ │ │ │ └── client.tsx
│ │ │ │ ├── competitor_finder
│ │ │ │ ├── base.ts
│ │ │ │ └── client.tsx
│ │ │ │ ├── github_search
│ │ │ │ ├── base.ts
│ │ │ │ └── client.tsx
│ │ │ │ ├── linkedin_search
│ │ │ │ ├── base.ts
│ │ │ │ └── client.tsx
│ │ │ │ ├── wikipedia_search
│ │ │ │ ├── base.ts
│ │ │ │ └── client.tsx
│ │ │ │ ├── research_paper_search
│ │ │ │ ├── base.ts
│ │ │ │ └── client.tsx
│ │ │ │ └── company_research
│ │ │ │ ├── base.ts
│ │ │ │ └── client.tsx
│ │ ├── spotify
│ │ │ ├── tools
│ │ │ │ ├── index.ts
│ │ │ │ ├── tracks
│ │ │ │ │ ├── base.ts
│ │ │ │ │ └── server.ts
│ │ │ │ └── playlists
│ │ │ │ │ └── base.ts
│ │ │ ├── base.ts
│ │ │ └── components
│ │ │ │ └── tool-call-display.tsx
│ │ ├── google-calendar
│ │ │ ├── tools
│ │ │ │ ├── find-availability
│ │ │ │ │ ├── lib
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ └── server.ts
│ │ │ │ ├── get-calendar
│ │ │ │ │ ├── base.ts
│ │ │ │ │ ├── server.ts
│ │ │ │ │ └── client.tsx
│ │ │ │ ├── get-event
│ │ │ │ │ ├── base.ts
│ │ │ │ │ ├── server.ts
│ │ │ │ │ └── client.tsx
│ │ │ │ ├── client.ts
│ │ │ │ ├── server.ts
│ │ │ │ ├── create-event
│ │ │ │ │ └── base.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── list-calendars
│ │ │ │ │ ├── base.ts
│ │ │ │ │ └── server.ts
│ │ │ │ └── list-events
│ │ │ │ │ └── server.ts
│ │ │ ├── lib
│ │ │ │ ├── calendar-client.ts
│ │ │ │ └── index.ts
│ │ │ ├── components
│ │ │ │ └── tool-call.tsx
│ │ │ └── base.ts
│ │ ├── components
│ │ │ └── link.tsx
│ │ └── strava
│ │ │ ├── tools
│ │ │ ├── stats
│ │ │ │ ├── base.ts
│ │ │ │ └── server.ts
│ │ │ ├── zones
│ │ │ │ ├── base.ts
│ │ │ │ └── server.ts
│ │ │ ├── profile
│ │ │ │ ├── base.ts
│ │ │ │ └── server.ts
│ │ │ ├── segment
│ │ │ │ ├── base.ts
│ │ │ │ └── server.ts
│ │ │ ├── routes
│ │ │ │ ├── base.ts
│ │ │ │ └── server.ts
│ │ │ ├── activity-details
│ │ │ │ ├── base.ts
│ │ │ │ └── server.ts
│ │ │ ├── explore-segments
│ │ │ │ ├── base.ts
│ │ │ │ └── server.ts
│ │ │ ├── activities
│ │ │ │ ├── server.ts
│ │ │ │ └── base.ts
│ │ │ └── index.ts
│ │ │ └── base.ts
│ ├── toolkit-groups.ts
│ └── create-tool.ts
├── app
│ ├── (general)
│ │ ├── account
│ │ │ ├── components
│ │ │ │ ├── tabs
│ │ │ │ │ ├── attachments
│ │ │ │ │ │ ├── attachment.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── images
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── videos
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ └── memories
│ │ │ │ │ │ └── index.tsx
│ │ │ │ └── header.tsx
│ │ │ └── page.tsx
│ │ ├── workbench
│ │ │ ├── new
│ │ │ │ ├── _components
│ │ │ │ │ └── index.ts
│ │ │ │ └── page.tsx
│ │ │ └── [id]
│ │ │ │ ├── edit
│ │ │ │ └── page.tsx
│ │ │ │ ├── page.tsx
│ │ │ │ ├── [chatId]
│ │ │ │ └── page.tsx
│ │ │ │ ├── layout.tsx
│ │ │ │ └── _components
│ │ │ │ └── header.tsx
│ │ ├── _components
│ │ │ ├── landing-page
│ │ │ │ ├── dependencies
│ │ │ │ │ └── types.ts
│ │ │ │ ├── workbench-examples
│ │ │ │ │ ├── types.ts
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── data.tsx
│ │ │ │ ├── sections.ts
│ │ │ │ ├── lib
│ │ │ │ │ ├── section.tsx
│ │ │ │ │ └── handle.tsx
│ │ │ │ ├── vision
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── workbenches
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── contributors
│ │ │ │ │ └── user-avatar-circles.tsx
│ │ │ │ ├── hero
│ │ │ │ │ └── graphic
│ │ │ │ │ │ └── toolkit-node.tsx
│ │ │ │ ├── banner
│ │ │ │ │ └── index.tsx
│ │ │ │ └── top-toolkits
│ │ │ │ │ └── index.tsx
│ │ │ ├── chat
│ │ │ │ ├── layout.tsx
│ │ │ │ └── messages
│ │ │ │ │ ├── utils
│ │ │ │ │ └── llm-code-block.tsx
│ │ │ │ │ └── greeting.tsx
│ │ │ └── sidebar
│ │ │ │ └── main.tsx
│ │ ├── _hooks
│ │ │ ├── use-star-chat.ts
│ │ │ ├── use-delete-chat.ts
│ │ │ ├── use-chat-visibility.ts
│ │ │ ├── use-delete-messages.tsx
│ │ │ └── use-messages.tsx
│ │ ├── page.tsx
│ │ ├── layout.tsx
│ │ ├── login
│ │ │ └── page.tsx
│ │ └── [id]
│ │ │ └── page.tsx
│ ├── icon1.png
│ ├── favicon.ico
│ ├── apple-icon.png
│ ├── opengraph-image.png
│ ├── twitter-image.png
│ ├── admin
│ │ ├── page.tsx
│ │ ├── toolkits
│ │ │ └── _components
│ │ │ │ └── sync-button.tsx
│ │ └── layout.tsx
│ ├── api
│ │ ├── auth
│ │ │ ├── [...nextauth]
│ │ │ │ └── route.ts
│ │ │ └── guest
│ │ │ │ └── route.ts
│ │ └── trpc
│ │ │ └── [trpc]
│ │ │ └── route.ts
│ ├── _components
│ │ └── navbar
│ │ │ ├── account-button
│ │ │ ├── index.tsx
│ │ │ └── provider-icon.tsx
│ │ │ ├── color-mode-toggle.tsx
│ │ │ └── index.tsx
│ └── manifest.ts
├── components
│ ├── ui
│ │ ├── logo
│ │ │ ├── index.ts
│ │ │ └── static.tsx
│ │ ├── skeleton.tsx
│ │ ├── model-icon.tsx
│ │ ├── code
│ │ │ ├── shared.ts
│ │ │ └── codegen.ts
│ │ ├── sonner.tsx
│ │ ├── merit-logo.tsx
│ │ ├── stack.tsx
│ │ ├── textarea.tsx
│ │ ├── separator.tsx
│ │ ├── label.tsx
│ │ ├── input.tsx
│ │ └── info-tooltip.tsx
│ ├── toolkit
│ │ └── types.ts
│ └── magicui
│ │ └── animated-shiny-text.tsx
├── ai
│ ├── video
│ │ ├── index.ts
│ │ ├── key-map.ts
│ │ ├── types.ts
│ │ ├── models
│ │ │ └── luma.ts
│ │ └── generate.ts
│ ├── language
│ │ ├── provider.ts
│ │ ├── models
│ │ │ ├── index.ts
│ │ │ ├── all.ts
│ │ │ ├── qwen.ts
│ │ │ ├── perplexity.ts
│ │ │ └── deepseek.ts
│ │ ├── index.ts
│ │ ├── types.ts
│ │ └── generate.ts
│ └── image
│ │ ├── types.ts
│ │ ├── key-map.ts
│ │ ├── models
│ │ ├── xai.ts
│ │ ├── openai.ts
│ │ ├── luma.ts
│ │ ├── fireworks.ts
│ │ └── fal.ts
│ │ ├── registry.ts
│ │ ├── index.ts
│ │ └── generate.ts
├── lib
│ ├── cookies
│ │ ├── keys.ts
│ │ └── types.ts
│ ├── utils.ts
│ ├── fetch.ts
│ └── constants.ts
├── server
│ ├── auth
│ │ └── index.ts
│ ├── db.ts
│ └── api
│ │ └── routers
│ │ ├── index.ts
│ │ ├── credits.ts
│ │ ├── streams.ts
│ │ └── users.ts
├── contexts
│ └── env
│ │ └── index.tsx
├── trpc
│ ├── query-client.ts
│ └── server.ts
└── hooks
│ └── use-mobile.ts
├── banner.png
├── .vscode
└── settings.json
├── public
├── icons
│ ├── t3.png
│ ├── e2b.png
│ ├── fal.png
│ ├── luma.png
│ ├── mem0.png
│ ├── next.png
│ ├── qwen.png
│ ├── radix.png
│ ├── react.png
│ ├── redis.png
│ ├── tRPC.png
│ ├── x-ai.png
│ ├── xai.png
│ ├── zod.png
│ ├── discord.png
│ ├── google.png
│ ├── lucide.png
│ ├── motion.png
│ ├── openai.png
│ ├── prisma.png
│ ├── shadcn.png
│ ├── vercel.png
│ ├── anthropic.png
│ ├── deepseek.png
│ ├── fireworks.png
│ ├── meta-llama.png
│ ├── nextauth.png
│ ├── openrouter.png
│ ├── perplexity.png
│ ├── postgres.png
│ ├── recharts.png
│ ├── tailwind.png
│ └── tanstack.png
└── manifest
│ ├── web-app-manifest-192x192.png
│ └── web-app-manifest-512x512.png
├── postcss.config.js
├── .npmrc
├── prisma
└── migrations
│ ├── 20250721181107_optional_user_role
│ └── migration.sql
│ ├── 20250721180853_user_role
│ └── migration.sql
│ ├── 20250714211437_add_starring
│ └── migration.sql
│ ├── migration_lock.toml
│ ├── 20250731015740_videos
│ └── migration.sql
│ ├── 20250721015616_tool_usage
│ └── migration.sql
│ ├── 20250615144652_chat_branching
│ └── migration.sql
│ ├── 20250721181257_user_role_enum
│ └── migration.sql
│ ├── 20250613013025_images
│ └── migration.sql
│ ├── 20250608210029_streams
│ └── migration.sql
│ ├── 20250730234607_videos
│ └── migration.sql
│ ├── 20250721200114_update_tool_schema
│ └── migration.sql
│ ├── 20250612033842_files
│ └── migration.sql
│ ├── 20250616064236_workbenches
│ └── migration.sql
│ ├── 20250721030057_tools_and_toolkiits
│ └── migration.sql
│ ├── 20250608175206_chats
│ └── migration.sql
│ └── 20250615224432_features
│ └── migration.sql
├── setup
├── steps
│ ├── index.ts
│ ├── 4_database.ts
│ └── 2_dependencies.ts
└── types.ts
├── vercel.json
├── prettier.config.js
├── components.json
├── next.config.js
├── .gitignore
├── .github
└── workflows
│ └── ci.yml
├── tsconfig.json
├── LICENSE
└── docker-compose.yml
/src/toolkits/toolkits/toolkit-types.ts:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/app/(general)/account/components/tabs/attachments/attachment.tsx:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/banner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonhedman/toolkit.dev/HEAD/banner.png
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "typescript.tsdk": "node_modules/typescript/lib"
3 | }
4 |
--------------------------------------------------------------------------------
/src/app/icon1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonhedman/toolkit.dev/HEAD/src/app/icon1.png
--------------------------------------------------------------------------------
/src/components/ui/logo/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./static";
2 | export * from "./animated";
3 |
--------------------------------------------------------------------------------
/public/icons/t3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonhedman/toolkit.dev/HEAD/public/icons/t3.png
--------------------------------------------------------------------------------
/src/app/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonhedman/toolkit.dev/HEAD/src/app/favicon.ico
--------------------------------------------------------------------------------
/public/icons/e2b.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonhedman/toolkit.dev/HEAD/public/icons/e2b.png
--------------------------------------------------------------------------------
/public/icons/fal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonhedman/toolkit.dev/HEAD/public/icons/fal.png
--------------------------------------------------------------------------------
/public/icons/luma.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonhedman/toolkit.dev/HEAD/public/icons/luma.png
--------------------------------------------------------------------------------
/public/icons/mem0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonhedman/toolkit.dev/HEAD/public/icons/mem0.png
--------------------------------------------------------------------------------
/public/icons/next.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonhedman/toolkit.dev/HEAD/public/icons/next.png
--------------------------------------------------------------------------------
/public/icons/qwen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonhedman/toolkit.dev/HEAD/public/icons/qwen.png
--------------------------------------------------------------------------------
/public/icons/radix.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonhedman/toolkit.dev/HEAD/public/icons/radix.png
--------------------------------------------------------------------------------
/public/icons/react.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonhedman/toolkit.dev/HEAD/public/icons/react.png
--------------------------------------------------------------------------------
/public/icons/redis.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonhedman/toolkit.dev/HEAD/public/icons/redis.png
--------------------------------------------------------------------------------
/public/icons/tRPC.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonhedman/toolkit.dev/HEAD/public/icons/tRPC.png
--------------------------------------------------------------------------------
/public/icons/x-ai.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonhedman/toolkit.dev/HEAD/public/icons/x-ai.png
--------------------------------------------------------------------------------
/public/icons/xai.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonhedman/toolkit.dev/HEAD/public/icons/xai.png
--------------------------------------------------------------------------------
/public/icons/zod.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonhedman/toolkit.dev/HEAD/public/icons/zod.png
--------------------------------------------------------------------------------
/src/app/apple-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonhedman/toolkit.dev/HEAD/src/app/apple-icon.png
--------------------------------------------------------------------------------
/src/toolkits/toolkits/e2b/tools/tools.ts:
--------------------------------------------------------------------------------
1 | export enum E2BTools {
2 | RunCode = "run-code",
3 | }
4 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | export default {
2 | plugins: {
3 | "@tailwindcss/postcss": {},
4 | },
5 | };
6 |
--------------------------------------------------------------------------------
/public/icons/discord.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonhedman/toolkit.dev/HEAD/public/icons/discord.png
--------------------------------------------------------------------------------
/public/icons/google.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonhedman/toolkit.dev/HEAD/public/icons/google.png
--------------------------------------------------------------------------------
/public/icons/lucide.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonhedman/toolkit.dev/HEAD/public/icons/lucide.png
--------------------------------------------------------------------------------
/public/icons/motion.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonhedman/toolkit.dev/HEAD/public/icons/motion.png
--------------------------------------------------------------------------------
/public/icons/openai.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonhedman/toolkit.dev/HEAD/public/icons/openai.png
--------------------------------------------------------------------------------
/public/icons/prisma.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonhedman/toolkit.dev/HEAD/public/icons/prisma.png
--------------------------------------------------------------------------------
/public/icons/shadcn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonhedman/toolkit.dev/HEAD/public/icons/shadcn.png
--------------------------------------------------------------------------------
/public/icons/vercel.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonhedman/toolkit.dev/HEAD/public/icons/vercel.png
--------------------------------------------------------------------------------
/src/toolkits/toolkits/image/tools/tools.ts:
--------------------------------------------------------------------------------
1 | export enum ImageTools {
2 | Generate = "generate",
3 | }
4 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/notion/components/index.ts:
--------------------------------------------------------------------------------
1 | export { ToolCallDisplay } from "./tool-call-display";
2 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | public-hoist-pattern[]=*eslint*
2 | public-hoist-pattern[]=*prettier*
3 | public-hoist-pattern[]=@shikijs/*
--------------------------------------------------------------------------------
/public/icons/anthropic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonhedman/toolkit.dev/HEAD/public/icons/anthropic.png
--------------------------------------------------------------------------------
/public/icons/deepseek.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonhedman/toolkit.dev/HEAD/public/icons/deepseek.png
--------------------------------------------------------------------------------
/public/icons/fireworks.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonhedman/toolkit.dev/HEAD/public/icons/fireworks.png
--------------------------------------------------------------------------------
/public/icons/meta-llama.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonhedman/toolkit.dev/HEAD/public/icons/meta-llama.png
--------------------------------------------------------------------------------
/public/icons/nextauth.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonhedman/toolkit.dev/HEAD/public/icons/nextauth.png
--------------------------------------------------------------------------------
/public/icons/openrouter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonhedman/toolkit.dev/HEAD/public/icons/openrouter.png
--------------------------------------------------------------------------------
/public/icons/perplexity.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonhedman/toolkit.dev/HEAD/public/icons/perplexity.png
--------------------------------------------------------------------------------
/public/icons/postgres.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonhedman/toolkit.dev/HEAD/public/icons/postgres.png
--------------------------------------------------------------------------------
/public/icons/recharts.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonhedman/toolkit.dev/HEAD/public/icons/recharts.png
--------------------------------------------------------------------------------
/public/icons/tailwind.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonhedman/toolkit.dev/HEAD/public/icons/tailwind.png
--------------------------------------------------------------------------------
/public/icons/tanstack.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonhedman/toolkit.dev/HEAD/public/icons/tanstack.png
--------------------------------------------------------------------------------
/src/app/(general)/workbench/new/_components/index.ts:
--------------------------------------------------------------------------------
1 | export { NewWorkbenchForm } from "./new-workbench-form";
2 |
--------------------------------------------------------------------------------
/src/app/opengraph-image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonhedman/toolkit.dev/HEAD/src/app/opengraph-image.png
--------------------------------------------------------------------------------
/src/app/twitter-image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonhedman/toolkit.dev/HEAD/src/app/twitter-image.png
--------------------------------------------------------------------------------
/src/toolkits/toolkits/etsy/tools/tools.ts:
--------------------------------------------------------------------------------
1 | export enum EtsyTools {
2 | getListings = "get-listings",
3 | }
4 |
--------------------------------------------------------------------------------
/src/app/admin/page.tsx:
--------------------------------------------------------------------------------
1 | export default function AdminDashboard() {
2 | return
Admin Dashboard
;
3 | }
4 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/github/tools/client.ts:
--------------------------------------------------------------------------------
1 | export * from "./search/client";
2 | export * from "./repo/client";
3 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/github/tools/server.ts:
--------------------------------------------------------------------------------
1 | export * from "./repo/server";
2 | export * from "./search/server";
3 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/twitter/tools/client.ts:
--------------------------------------------------------------------------------
1 | export * from "./profile/client";
2 | export * from "./tweets/client";
3 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/twitter/tools/server.ts:
--------------------------------------------------------------------------------
1 | export * from "./profile/server";
2 | export * from "./tweets/server";
3 |
--------------------------------------------------------------------------------
/src/app/api/auth/[...nextauth]/route.ts:
--------------------------------------------------------------------------------
1 | import { handlers } from "@/server/auth";
2 |
3 | export const { GET, POST } = handlers;
4 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/discord/tools/client.ts:
--------------------------------------------------------------------------------
1 | export * from "./list-servers/client";
2 | export * from "./get-user-info/client";
3 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/discord/tools/server.ts:
--------------------------------------------------------------------------------
1 | export * from "./list-servers/server";
2 | export * from "./get-user-info/server";
3 |
--------------------------------------------------------------------------------
/prisma/migrations/20250721181107_optional_user_role/migration.sql:
--------------------------------------------------------------------------------
1 | -- AlterTable
2 | ALTER TABLE "User" ALTER COLUMN "role" DROP NOT NULL;
3 |
--------------------------------------------------------------------------------
/public/manifest/web-app-manifest-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonhedman/toolkit.dev/HEAD/public/manifest/web-app-manifest-192x192.png
--------------------------------------------------------------------------------
/public/manifest/web-app-manifest-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasonhedman/toolkit.dev/HEAD/public/manifest/web-app-manifest-512x512.png
--------------------------------------------------------------------------------
/src/ai/video/index.ts:
--------------------------------------------------------------------------------
1 | import { lumaVideoModels } from "./models/luma";
2 |
3 | export const allVideoModels = [...lumaVideoModels] as const;
4 |
--------------------------------------------------------------------------------
/prisma/migrations/20250721180853_user_role/migration.sql:
--------------------------------------------------------------------------------
1 | -- AlterTable
2 | ALTER TABLE "User" ADD COLUMN "role" TEXT NOT NULL DEFAULT 'user';
3 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/mem0/tools/tools.ts:
--------------------------------------------------------------------------------
1 | export enum Mem0Tools {
2 | AddMemory = "add-memory",
3 | SearchMemories = "search-memories",
4 | }
5 |
--------------------------------------------------------------------------------
/prisma/migrations/20250714211437_add_starring/migration.sql:
--------------------------------------------------------------------------------
1 | -- AlterTable
2 | ALTER TABLE "Chat" ADD COLUMN "starred" BOOLEAN NOT NULL DEFAULT false;
3 |
--------------------------------------------------------------------------------
/setup/steps/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./1_environment";
2 | export * from "./2_dependencies";
3 | export * from "./3_docker";
4 | export * from "./4_database";
5 |
--------------------------------------------------------------------------------
/src/app/(general)/_components/landing-page/dependencies/types.ts:
--------------------------------------------------------------------------------
1 | export interface Dependency {
2 | name: string;
3 | icon: React.ReactNode | null;
4 | }
5 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/video/tools/index.ts:
--------------------------------------------------------------------------------
1 | export enum VideoTools {
2 | Generate = "generate",
3 | }
4 |
5 | export { baseGenerateTool } from "./generate/base";
6 |
--------------------------------------------------------------------------------
/prisma/migrations/migration_lock.toml:
--------------------------------------------------------------------------------
1 | # Please do not edit this file manually
2 | # It should be added in your version-control system (e.g., Git)
3 | provider = "postgresql"
4 |
--------------------------------------------------------------------------------
/src/app/(general)/account/components/tabs/images/index.tsx:
--------------------------------------------------------------------------------
1 | import { ImagesTable } from "./table";
2 |
3 | export const Images = () => {
4 | return ;
5 | };
6 |
--------------------------------------------------------------------------------
/src/app/(general)/account/components/tabs/videos/index.tsx:
--------------------------------------------------------------------------------
1 | import { VideosTable } from "./table";
2 |
3 | export const Videos = () => {
4 | return ;
5 | };
6 |
--------------------------------------------------------------------------------
/vercel.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://openapi.vercel.sh/vercel.json",
3 | "git": {
4 | "deploymentEnabled": {
5 | "!main": false
6 | }
7 | }
8 | }
--------------------------------------------------------------------------------
/src/ai/video/key-map.ts:
--------------------------------------------------------------------------------
1 | import type { VideoModelProvider } from "./types";
2 |
3 | export const videoKeyMap: Record = {
4 | luma: "LUMA_API_KEY",
5 | };
6 |
--------------------------------------------------------------------------------
/src/ai/video/types.ts:
--------------------------------------------------------------------------------
1 | export type VideoModelProvider = "luma";
2 |
3 | export type VideoModel = {
4 | name: string;
5 | provider: VideoModelProvider;
6 | modelId: string;
7 | };
8 |
--------------------------------------------------------------------------------
/src/app/(general)/account/components/tabs/memories/index.tsx:
--------------------------------------------------------------------------------
1 | import { MemoriesTable } from "./table";
2 |
3 | export const Memories = () => {
4 | return ;
5 | };
6 |
--------------------------------------------------------------------------------
/prettier.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('prettier').Config & import('prettier-plugin-tailwindcss').PluginOptions} */
2 | export default {
3 | plugins: ["prettier-plugin-tailwindcss"],
4 | };
5 |
--------------------------------------------------------------------------------
/src/app/(general)/account/components/tabs/attachments/index.tsx:
--------------------------------------------------------------------------------
1 | import { DataTableDemo } from "./table";
2 |
3 | export const Attachments = async () => {
4 | return ;
5 | };
6 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/google-drive/tools/client.ts:
--------------------------------------------------------------------------------
1 | export { googleDriveSearchFilesToolConfigClient } from "./search-files/client";
2 | export { googleDriveReadFileToolConfigClient } from "./read-file/client";
3 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/google-drive/tools/server.ts:
--------------------------------------------------------------------------------
1 | export { googleDriveSearchFilesToolConfigServer } from "./search-files/server";
2 | export { googleDriveReadFileToolConfigServer } from "./read-file/server";
3 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/exa/components/index.ts:
--------------------------------------------------------------------------------
1 | export { ToolCallDisplay } from "./tool-call-display";
2 | export { ResultItem, type ResultData } from "./result-item";
3 | export { ResultsList } from "./results-list";
4 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/discord/tools/index.ts:
--------------------------------------------------------------------------------
1 | export enum DiscordTools {
2 | ListServers = "list-servers",
3 | GetUserInfo = "get-user-info",
4 | }
5 |
6 | export * from "./list-servers/base";
7 | export * from "./get-user-info/base";
8 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/twitter/tools/index.ts:
--------------------------------------------------------------------------------
1 | export enum TwitterTools {
2 | GetUserProfile = "get-user-profile",
3 | GetLatestTweets = "get-latest-tweets",
4 | }
5 |
6 | export * from "./profile/base";
7 | export * from "./tweets/base";
8 |
--------------------------------------------------------------------------------
/prisma/migrations/20250731015740_videos/migration.sql:
--------------------------------------------------------------------------------
1 | /*
2 | Warnings:
3 |
4 | - You are about to drop the column `size` on the `Video` table. All the data in the column will be lost.
5 |
6 | */
7 | -- AlterTable
8 | ALTER TABLE "Video" DROP COLUMN "size";
9 |
--------------------------------------------------------------------------------
/src/ai/language/provider.ts:
--------------------------------------------------------------------------------
1 | import { createOpenRouter } from "@openrouter/ai-sdk-provider";
2 |
3 | export const openrouter = createOpenRouter({
4 | headers: {
5 | "HTTP-Referer": "https://toolkit.dev",
6 | "X-Title": "Toolkit.dev",
7 | },
8 | });
9 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/spotify/tools/index.ts:
--------------------------------------------------------------------------------
1 | export enum SpotifyTools {
2 | GetPlaylists = "get-playlists",
3 | GetTracks = "get-tracks",
4 | }
5 |
6 | export { getPlaylistsBase } from "./playlists/base";
7 | export { getTracksBase } from "./tracks/base";
8 |
--------------------------------------------------------------------------------
/src/lib/cookies/keys.ts:
--------------------------------------------------------------------------------
1 | export const COOKIE_KEYS = {
2 | SELECTED_CHAT_MODEL: "open-chat-selected-model",
3 | IMAGE_GENERATION_MODEL: "open-chat-image-model",
4 | USE_NATIVE_SEARCH: "open-chat-native-search",
5 | TOOLKITS: "open-chat-toolkits",
6 | } as const;
7 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/google-drive/tools/index.ts:
--------------------------------------------------------------------------------
1 | export enum GoogleDriveTools {
2 | SearchFiles = "search-files",
3 | ReadFile = "read-file",
4 | }
5 |
6 | export { searchFilesTool } from "./search-files/base";
7 | export { readFileTool } from "./read-file/base";
8 |
--------------------------------------------------------------------------------
/src/ai/image/types.ts:
--------------------------------------------------------------------------------
1 | export type ImageModelProvider =
2 | | "openai"
3 | | "xai"
4 | | "fal"
5 | | "fireworks"
6 | | "luma";
7 |
8 | export type ImageModel = {
9 | name: string;
10 | provider: ImageModelProvider;
11 | modelId: string;
12 | };
13 |
--------------------------------------------------------------------------------
/src/components/toolkit/types.ts:
--------------------------------------------------------------------------------
1 | import type { Toolkits } from "@/toolkits/toolkits/shared";
2 | import type { ClientToolkit } from "@/toolkits/types";
3 |
4 | export type SelectedToolkit = {
5 | id: Toolkits;
6 | toolkit: ClientToolkit;
7 | parameters: Record;
8 | };
9 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/github/tools/index.ts:
--------------------------------------------------------------------------------
1 | export enum GithubTools {
2 | SearchRepos = "search-repos",
3 | SearchCode = "search-code",
4 | SearchUsers = "search-users",
5 | RepoInfo = "repo-info",
6 | }
7 |
8 | export * from "./search/base";
9 | export * from "./repo/base";
10 |
--------------------------------------------------------------------------------
/src/app/(general)/_components/chat/layout.tsx:
--------------------------------------------------------------------------------
1 | interface Props {
2 | children: React.ReactNode;
3 | }
4 |
5 | export const ChatLayout: React.FC = ({ children }) => {
6 | return (
7 | {children}
8 | );
9 | };
10 |
--------------------------------------------------------------------------------
/src/ai/image/key-map.ts:
--------------------------------------------------------------------------------
1 | import type { ImageModelProvider } from "./types";
2 |
3 | export const imageKeyMap: Record = {
4 | openai: "OPENAI_API_KEY",
5 | xai: "XAI_API_KEY",
6 | fal: "FAL_API_KEY",
7 | fireworks: "FIREWORKS_API_KEY",
8 | luma: "LUMA_API_KEY",
9 | };
10 |
--------------------------------------------------------------------------------
/src/app/(general)/_components/landing-page/workbench-examples/types.ts:
--------------------------------------------------------------------------------
1 | import type { Toolkits } from "@/toolkits/toolkits/shared";
2 | import type { LucideIcon } from "lucide-react";
3 |
4 | export interface WorkbenchExample {
5 | title: string;
6 | systemPrompt: string;
7 | toolkits: Toolkits[];
8 | icon: LucideIcon;
9 | }
10 |
--------------------------------------------------------------------------------
/src/server/auth/index.ts:
--------------------------------------------------------------------------------
1 | import { cache } from "react";
2 |
3 | import NextAuth from "next-auth";
4 |
5 | import { authConfig } from "./config";
6 |
7 | const { auth: uncachedAuth, handlers, signIn, signOut } = NextAuth(authConfig);
8 |
9 | const auth = cache(uncachedAuth);
10 |
11 | export { auth, handlers, signIn, signOut };
12 |
--------------------------------------------------------------------------------
/src/app/(general)/_hooks/use-star-chat.ts:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { api } from "@/trpc/react";
4 |
5 | export const useStarChat = () => {
6 | const utils = api.useUtils();
7 |
8 | return api.chats.starChat.useMutation({
9 | onSuccess: async () => {
10 | await utils.chats.getChats.invalidate();
11 | },
12 | });
13 | };
14 |
--------------------------------------------------------------------------------
/src/app/(general)/_hooks/use-delete-chat.ts:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { api } from "@/trpc/react";
4 |
5 | export const useDeleteChat = () => {
6 | const utils = api.useUtils();
7 |
8 | return api.chats.deleteChat.useMutation({
9 | onSuccess: async () => {
10 | await utils.chats.getChats.invalidate();
11 | },
12 | });
13 | };
14 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/github/lib/prs.ts:
--------------------------------------------------------------------------------
1 | import { type Octokit } from "octokit";
2 |
3 | export const getTotalPrs = async (octokit: Octokit, query: string) => {
4 | const {
5 | data: { total_count },
6 | } = await octokit.rest.search.issuesAndPullRequests({
7 | q: query,
8 | per_page: 1,
9 | });
10 |
11 | return total_count;
12 | };
13 |
--------------------------------------------------------------------------------
/src/components/ui/skeleton.tsx:
--------------------------------------------------------------------------------
1 | import { cn } from "@/lib/utils";
2 |
3 | function Skeleton({ className, ...props }: React.ComponentProps<"div">) {
4 | return (
5 |
10 | );
11 | }
12 |
13 | export { Skeleton };
14 |
--------------------------------------------------------------------------------
/src/ai/image/models/xai.ts:
--------------------------------------------------------------------------------
1 | import type { ImageModel } from "../types";
2 |
3 | const xaiImageModelData: Omit[] = [
4 | {
5 | name: "Grok 2 Image",
6 | modelId: "grok-2-image",
7 | },
8 | ];
9 |
10 | export const xaiImageModels: ImageModel[] = xaiImageModelData.map((model) => ({
11 | ...model,
12 | provider: "xai",
13 | }));
14 |
--------------------------------------------------------------------------------
/src/app/(general)/_hooks/use-chat-visibility.ts:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { api } from "@/trpc/react";
4 |
5 | export const useUpdateChatVisibility = () => {
6 | const utils = api.useUtils();
7 |
8 | return api.chats.updateChatVisibility.useMutation({
9 | onSuccess: async () => {
10 | await utils.chats.getChats.invalidate();
11 | },
12 | });
13 | };
14 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/google-calendar/tools/find-availability/lib/index.ts:
--------------------------------------------------------------------------------
1 | export { generateTimeSlots } from "./slot-generator";
2 | export {
3 | hasConflict,
4 | filterConflictingSlots,
5 | extractConflictingEvents,
6 | } from "./conflict-detector";
7 | export { resolveAttendeeEmails } from "./attendee-resolver";
8 | export { analyzeAvailability } from "./analyze-availability";
9 |
--------------------------------------------------------------------------------
/src/app/(general)/workbench/new/page.tsx:
--------------------------------------------------------------------------------
1 | import { auth } from "@/server/auth";
2 | import { redirect } from "next/navigation";
3 | import { NewWorkbenchForm } from "./_components";
4 |
5 | export default async function NewWorkbenchPage() {
6 | const session = await auth();
7 |
8 | if (!session) {
9 | redirect("/");
10 | }
11 |
12 | return ;
13 | }
14 |
--------------------------------------------------------------------------------
/prisma/migrations/20250721015616_tool_usage/migration.sql:
--------------------------------------------------------------------------------
1 | -- CreateTable
2 | CREATE TABLE "ToolUsage" (
3 | "toolkit" TEXT NOT NULL,
4 | "tool" TEXT NOT NULL,
5 | "count" INTEGER NOT NULL,
6 | "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
7 | "updatedAt" TIMESTAMP(3) NOT NULL,
8 |
9 | CONSTRAINT "ToolUsage_pkey" PRIMARY KEY ("toolkit","tool")
10 | );
11 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/exa/tools/tools.ts:
--------------------------------------------------------------------------------
1 | export enum ExaTools {
2 | Search = "search",
3 | ResearchPaperSearch = "research-paper-search",
4 | CompanyResearch = "company-research",
5 | Crawling = "crawling",
6 | CompetitorFinder = "competitor-finder",
7 | LinkedinSearch = "linkedin-search",
8 | WikipediaSearch = "wikipedia-search-exa",
9 | GithubSearch = "github-search",
10 | }
11 |
--------------------------------------------------------------------------------
/src/ai/image/models/openai.ts:
--------------------------------------------------------------------------------
1 | import type { ImageModel } from "../types";
2 |
3 | const openAiImageModelsData: Omit[] = [
4 | {
5 | name: "GPT Image",
6 | modelId: "gpt-image-1",
7 | },
8 | ];
9 |
10 | export const openAiImageModels: ImageModel[] = openAiImageModelsData.map(
11 | (model) => ({
12 | ...model,
13 | provider: "openai",
14 | }),
15 | );
16 |
--------------------------------------------------------------------------------
/prisma/migrations/20250615144652_chat_branching/migration.sql:
--------------------------------------------------------------------------------
1 | -- AlterTable
2 | ALTER TABLE "Chat" ADD COLUMN "parentChatId" TEXT;
3 |
4 | -- AlterTable
5 | ALTER TABLE "Message" ADD COLUMN "modelId" TEXT NOT NULL DEFAULT 'openai:gpt-4o';
6 |
7 | -- AddForeignKey
8 | ALTER TABLE "Chat" ADD CONSTRAINT "Chat_parentChatId_fkey" FOREIGN KEY ("parentChatId") REFERENCES "Chat"("id") ON DELETE CASCADE ON UPDATE CASCADE;
9 |
--------------------------------------------------------------------------------
/prisma/migrations/20250721181257_user_role_enum/migration.sql:
--------------------------------------------------------------------------------
1 | /*
2 | Warnings:
3 |
4 | - The `role` column on the `User` table would be dropped and recreated. This will lead to data loss if there is data in the column.
5 |
6 | */
7 | -- CreateEnum
8 | CREATE TYPE "UserRole" AS ENUM ('USER', 'ADMIN');
9 |
10 | -- AlterTable
11 | ALTER TABLE "User" DROP COLUMN "role",
12 | ADD COLUMN "role" "UserRole" DEFAULT 'USER';
13 |
--------------------------------------------------------------------------------
/src/app/(general)/_hooks/use-delete-messages.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { api } from "@/trpc/react";
4 |
5 | export const useDeleteMessagesAfterTimestamp = () => {
6 | const utils = api.useUtils();
7 |
8 | return api.messages.deleteMessagesAfterTimestamp.useMutation({
9 | onSuccess: async (_, { chatId }) => {
10 | await utils.messages.getMessagesForChat.invalidate({ chatId });
11 | },
12 | });
13 | };
14 |
--------------------------------------------------------------------------------
/src/ai/image/registry.ts:
--------------------------------------------------------------------------------
1 | import { createProviderRegistry } from "ai";
2 |
3 | import { openai } from "@ai-sdk/openai";
4 | import { xai } from "@ai-sdk/xai";
5 | import { fireworks } from "@ai-sdk/fireworks";
6 | import { fal } from "@ai-sdk/fal";
7 | import { luma } from "@ai-sdk/luma";
8 |
9 | export const imageModelRegistry = createProviderRegistry({
10 | openai,
11 | xai,
12 | fireworks,
13 | fal,
14 | luma,
15 | });
16 |
--------------------------------------------------------------------------------
/src/app/(general)/_components/landing-page/sections.ts:
--------------------------------------------------------------------------------
1 | export const SECTIONS = {
2 | Hero: "Hero",
3 | Vision: "Vision",
4 | Merit: "Merit",
5 | Contributors: "Contributors",
6 | Features: "Features",
7 | TopToolkits: "TopToolkits",
8 | ToolkitCreation: "ToolkitCreation",
9 | Workbench: "Workbench",
10 | WorkbenchExamples: "WorkbenchExamples",
11 | Dependencies: "Dependencies",
12 | Roadmap: "Roadmap",
13 | } as const;
14 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/components/link.tsx:
--------------------------------------------------------------------------------
1 | import BaseLink from "next/link";
2 |
3 | export const Link = ({
4 | href,
5 | children,
6 | }: {
7 | href: string;
8 | children: string;
9 | }) => {
10 | return (
11 |
17 | {children}
18 |
19 | );
20 | };
21 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/strava/tools/stats/base.ts:
--------------------------------------------------------------------------------
1 | import { z } from "zod";
2 |
3 | import { createBaseTool } from "@/toolkits/create-tool";
4 |
5 | import type { ActivityStats } from "strava";
6 |
7 | export const getAthleteStatsBase = createBaseTool({
8 | description: "Get the authenticated athlete's statistics",
9 | inputSchema: z.object({}),
10 | outputSchema: z.object({
11 | stats: z.custom(),
12 | }),
13 | });
14 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/strava/tools/zones/base.ts:
--------------------------------------------------------------------------------
1 | import { z } from "zod";
2 |
3 | import { createBaseTool } from "@/toolkits/create-tool";
4 |
5 | import type { Zones } from "strava";
6 |
7 | export const getAthleteZonesBase = createBaseTool({
8 | description: "Get the authenticated athlete's heart rate and power zones",
9 | inputSchema: z.object({}),
10 | outputSchema: z.object({
11 | zones: z.custom(),
12 | }),
13 | });
14 |
--------------------------------------------------------------------------------
/src/lib/cookies/types.ts:
--------------------------------------------------------------------------------
1 | import type { LanguageModel } from "@/ai/language/types";
2 | import type { ImageModel } from "@/ai/image/types";
3 |
4 | export interface PersistedToolkit {
5 | id: string;
6 | parameters: Record;
7 | }
8 |
9 | export interface ChatPreferences {
10 | selectedChatModel?: LanguageModel;
11 | imageGenerationModel?: ImageModel;
12 | useNativeSearch?: boolean;
13 | toolkits?: PersistedToolkit[];
14 | }
15 |
--------------------------------------------------------------------------------
/src/ai/language/models/index.ts:
--------------------------------------------------------------------------------
1 | export { anthropicModels } from "./anthropic";
2 | export { googleModels } from "./google";
3 | export { openAiLanguageModels } from "./openai";
4 | export { xaiLanguageModels } from "./xai";
5 | export { perplexityModels } from "./perplexity";
6 | export { llamaModels } from "./llama";
7 | export { qwenModels } from "./qwen";
8 | export { deepseekModels } from "./deepseek";
9 | export { openRouterModels } from "./openrouter";
10 |
--------------------------------------------------------------------------------
/setup/steps/4_database.ts:
--------------------------------------------------------------------------------
1 | import { execSync } from "child_process";
2 |
3 | import { logSuccess, logError, getPackageManager } from "../utils";
4 |
5 | export function runMigrations(): void {
6 | try {
7 | execSync(`${getPackageManager()} db:generate`, { stdio: "ignore" });
8 | logSuccess("Database migrations completed successfully");
9 | } catch (error) {
10 | logError("Failed to run database migrations");
11 | throw error;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/ai/video/models/luma.ts:
--------------------------------------------------------------------------------
1 | import type { VideoModel } from "../types";
2 |
3 | const lumaVideoModelsData: Omit[] = [
4 | {
5 | name: "Ray 2 Flash",
6 | modelId: "ray-flash-2",
7 | },
8 | {
9 | name: "Ray 2",
10 | modelId: "ray-2",
11 | },
12 | ] as const;
13 |
14 | export const lumaVideoModels: VideoModel[] = lumaVideoModelsData.map(
15 | (model) => ({
16 | ...model,
17 | provider: "luma",
18 | }),
19 | );
20 |
--------------------------------------------------------------------------------
/src/ai/image/index.ts:
--------------------------------------------------------------------------------
1 | import { openAiImageModels } from "./models/openai";
2 | import { xaiImageModels } from "./models/xai";
3 | import { fireworksImageModels } from "./models/fireworks";
4 | import { falImageModels } from "./models/fal";
5 | import { lumaImageModels } from "./models/luma";
6 |
7 | export const allImageModels = [
8 | ...openAiImageModels,
9 | ...xaiImageModels,
10 | ...falImageModels,
11 | ...fireworksImageModels,
12 | ...lumaImageModels,
13 | ];
14 |
--------------------------------------------------------------------------------
/src/ai/image/models/luma.ts:
--------------------------------------------------------------------------------
1 | import type { ImageModel } from "../types";
2 |
3 | const lumaImageModelsData: Omit[] = [
4 | {
5 | name: "Photon 1",
6 | modelId: "photon-1",
7 | },
8 | {
9 | name: "Photon 1 Flash",
10 | modelId: "photon-flash-1",
11 | },
12 | ];
13 |
14 | export const lumaImageModels: ImageModel[] = lumaImageModelsData.map(
15 | (model) => ({
16 | ...model,
17 | provider: "luma",
18 | }),
19 | );
20 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/strava/tools/profile/base.ts:
--------------------------------------------------------------------------------
1 | import { z } from "zod";
2 |
3 | import { createBaseTool } from "@/toolkits/create-tool";
4 |
5 | import type { DetailedAthlete } from "strava";
6 |
7 | export const getAthleteBase = createBaseTool({
8 | description:
9 | "Get the authenticated athlete's profile information from Strava",
10 | inputSchema: z.object({}),
11 | outputSchema: z.object({
12 | athlete: z.custom(),
13 | }),
14 | });
15 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/etsy/tools/get-listings/base.ts:
--------------------------------------------------------------------------------
1 | import { z } from "zod";
2 | import { createBaseTool } from "@/toolkits/create-tool";
3 | import type { IShopListing } from "etsy-ts";
4 |
5 | export const getListings = createBaseTool({
6 | description:
7 | "Fetches all listings from the Etsy shop associated with the authenticated user.",
8 | inputSchema: z.object({}),
9 | outputSchema: z.object({
10 | results: z.array(z.custom()),
11 | }),
12 | });
13 |
--------------------------------------------------------------------------------
/src/ai/image/generate.ts:
--------------------------------------------------------------------------------
1 | import { experimental_generateImage as baseGenerateImage } from "ai";
2 |
3 | import { imageModelRegistry } from "./registry";
4 |
5 | import type { ImageModelProvider } from "./types";
6 |
7 | export const generateImage = async (
8 | model: `${ImageModelProvider}:${string}`,
9 | prompt: string,
10 | ) => {
11 | const { image } = await baseGenerateImage({
12 | model: imageModelRegistry.imageModel(model),
13 | prompt,
14 | });
15 |
16 | return image;
17 | };
18 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/e2b/base.ts:
--------------------------------------------------------------------------------
1 | import type { ToolkitConfig } from "@/toolkits/types";
2 | import { baseRunCodeTool } from "./tools/run_code/base";
3 | import { E2BTools } from "./tools/tools";
4 | import { z } from "zod";
5 |
6 | export const e2bParameters = z.object({});
7 |
8 | export const baseE2BToolkitConfig: ToolkitConfig<
9 | E2BTools,
10 | typeof e2bParameters.shape
11 | > = {
12 | tools: {
13 | [E2BTools.RunCode]: baseRunCodeTool,
14 | },
15 | parameters: e2bParameters,
16 | };
17 |
--------------------------------------------------------------------------------
/src/components/ui/model-icon.tsx:
--------------------------------------------------------------------------------
1 | import Image from "next/image";
2 |
3 | import { cn } from "@/lib/utils";
4 |
5 | interface Props {
6 | provider: string;
7 | className?: string;
8 | }
9 |
10 | export const ModelProviderIcon: React.FC = ({ provider, className }) => {
11 | return (
12 |
19 | );
20 | };
21 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/discord/tools/get-user-info/base.ts:
--------------------------------------------------------------------------------
1 | import { z } from "zod";
2 |
3 | import { createBaseTool } from "@/toolkits/create-tool";
4 |
5 | import type { APIUser } from "discord-api-types/v10";
6 |
7 | export const getUserInfoTool = createBaseTool({
8 | description: "Get information about your Discord account",
9 | inputSchema: z.object({
10 | // No input needed - uses authenticated user
11 | }),
12 | outputSchema: z.object({
13 | user: z.custom(),
14 | }),
15 | });
16 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/discord/tools/list-servers/base.ts:
--------------------------------------------------------------------------------
1 | import { z } from "zod";
2 | import { createBaseTool } from "@/toolkits/create-tool";
3 | import type { APIGuild } from "discord-api-types/v10";
4 |
5 | export const listServersTool = createBaseTool({
6 | description: "List all Discord servers you are a member of",
7 | inputSchema: z.object({
8 | // No input needed - uses authenticated user's servers
9 | }),
10 | outputSchema: z.object({
11 | servers: z.custom(),
12 | }),
13 | });
14 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/strava/tools/segment/base.ts:
--------------------------------------------------------------------------------
1 | import { z } from "zod";
2 |
3 | import { createBaseTool } from "@/toolkits/create-tool";
4 |
5 | import type { DetailedSegment } from "strava";
6 |
7 | export const getSegmentDetailsBase = createBaseTool({
8 | description: "Get detailed information about a specific segment",
9 | inputSchema: z.object({
10 | id: z.number().describe("The segment ID"),
11 | }),
12 | outputSchema: z.object({
13 | segment: z.custom(),
14 | }),
15 | });
16 |
--------------------------------------------------------------------------------
/prisma/migrations/20250613013025_images/migration.sql:
--------------------------------------------------------------------------------
1 | -- CreateTable
2 | CREATE TABLE "Image" (
3 | "id" TEXT NOT NULL,
4 | "userId" TEXT NOT NULL,
5 | "contentType" TEXT NOT NULL,
6 | "url" TEXT NOT NULL,
7 | "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
8 |
9 | CONSTRAINT "Image_pkey" PRIMARY KEY ("id")
10 | );
11 |
12 | -- AddForeignKey
13 | ALTER TABLE "Image" ADD CONSTRAINT "Image_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
14 |
--------------------------------------------------------------------------------
/components.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://ui.shadcn.com/schema.json",
3 | "style": "new-york",
4 | "rsc": true,
5 | "tsx": true,
6 | "tailwind": {
7 | "config": "",
8 | "css": "src/styles/globals.css",
9 | "baseColor": "neutral",
10 | "cssVariables": true,
11 | "prefix": ""
12 | },
13 | "aliases": {
14 | "components": "@/components",
15 | "utils": "@/lib/utils",
16 | "ui": "@/components/ui",
17 | "lib": "@/lib",
18 | "hooks": "@/hooks"
19 | },
20 | "iconLibrary": "lucide"
21 | }
--------------------------------------------------------------------------------
/prisma/migrations/20250608210029_streams/migration.sql:
--------------------------------------------------------------------------------
1 | -- CreateTable
2 | CREATE TABLE "Stream" (
3 | "id" TEXT NOT NULL,
4 | "chatId" TEXT NOT NULL,
5 | "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
6 |
7 | CONSTRAINT "Stream_pkey" PRIMARY KEY ("id")
8 | );
9 |
10 | -- CreateIndex
11 | CREATE INDEX "Stream_chatId_idx" ON "Stream"("chatId");
12 |
13 | -- AddForeignKey
14 | ALTER TABLE "Stream" ADD CONSTRAINT "Stream_chatId_fkey" FOREIGN KEY ("chatId") REFERENCES "Chat"("id") ON DELETE CASCADE ON UPDATE CASCADE;
15 |
--------------------------------------------------------------------------------
/src/ai/language/index.ts:
--------------------------------------------------------------------------------
1 | import {
2 | openAiLanguageModels,
3 | xaiLanguageModels,
4 | perplexityModels,
5 | googleModels,
6 | anthropicModels,
7 | llamaModels,
8 | qwenModels,
9 | deepseekModels,
10 | openRouterModels,
11 | } from "./models";
12 |
13 | export const languageModels = [
14 | ...anthropicModels,
15 | ...googleModels,
16 | ...openAiLanguageModels,
17 | ...xaiLanguageModels,
18 | ...perplexityModels,
19 | ...openRouterModels,
20 | ...llamaModels,
21 | ...qwenModels,
22 | ...deepseekModels,
23 | ];
24 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/google-calendar/tools/get-calendar/base.ts:
--------------------------------------------------------------------------------
1 | import { z } from "zod";
2 | import { createBaseTool } from "@/toolkits/create-tool";
3 | import type { calendar_v3 } from "googleapis";
4 |
5 | export const getCalendarTool = createBaseTool({
6 | description: "Get details of a specific calendar by ID",
7 | inputSchema: z.object({
8 | calendarId: z.string().describe("The ID of the calendar to retrieve"),
9 | }),
10 | outputSchema: z.object({
11 | calendar: z.custom(),
12 | }),
13 | });
14 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/etsy/base.ts:
--------------------------------------------------------------------------------
1 | import { z } from "zod";
2 |
3 | import { EtsyTools } from "./tools/tools";
4 |
5 | import { getListings } from "@/toolkits/toolkits/etsy/tools/get-listings/base";
6 |
7 | import type { ToolkitConfig } from "@/toolkits/types";
8 |
9 | export const etsyParameters = z.object({});
10 |
11 | export const baseEtsyToolkitConfig: ToolkitConfig<
12 | EtsyTools,
13 | typeof etsyParameters.shape
14 | > = {
15 | tools: {
16 | [EtsyTools.getListings]: getListings,
17 | },
18 | parameters: etsyParameters,
19 | };
20 |
--------------------------------------------------------------------------------
/src/app/(general)/_components/landing-page/lib/section.tsx:
--------------------------------------------------------------------------------
1 | import { cn } from "@/lib/utils";
2 | import React from "react";
3 | import type { SECTIONS } from "../sections";
4 |
5 | interface Props {
6 | id: (typeof SECTIONS)[keyof typeof SECTIONS];
7 | children: React.ReactNode;
8 | className?: string;
9 | }
10 |
11 | export const Section: React.FC = ({ id, className, children }) => {
12 | return (
13 |
16 | );
17 | };
18 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/video/tools/generate/base.ts:
--------------------------------------------------------------------------------
1 | import { z } from "zod";
2 | import { createBaseTool } from "@/toolkits/create-tool";
3 |
4 | const inputSchema = z.object({
5 | prompt: z.string().min(1).max(250).describe("The video generation prompt"),
6 | });
7 |
8 | const outputSchema = z.object({
9 | url: z.string().describe("The URL of the generated video"),
10 | });
11 |
12 | export const baseGenerateTool = createBaseTool({
13 | description: "Generate a video using Luma Labs Dream Machine",
14 | inputSchema,
15 | outputSchema,
16 | });
17 |
--------------------------------------------------------------------------------
/prisma/migrations/20250730234607_videos/migration.sql:
--------------------------------------------------------------------------------
1 | -- CreateTable
2 | CREATE TABLE "Video" (
3 | "id" TEXT NOT NULL,
4 | "userId" TEXT NOT NULL,
5 | "url" TEXT NOT NULL,
6 | "size" INTEGER NOT NULL,
7 | "modelId" TEXT NOT NULL DEFAULT 'ray-2',
8 | "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
9 |
10 | CONSTRAINT "Video_pkey" PRIMARY KEY ("id")
11 | );
12 |
13 | -- AddForeignKey
14 | ALTER TABLE "Video" ADD CONSTRAINT "Video_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
15 |
--------------------------------------------------------------------------------
/src/toolkits/toolkit-groups.ts:
--------------------------------------------------------------------------------
1 | import { Logo } from "@/components/ui/logo";
2 | import { ToolkitGroups, type ToolkitGroup } from "./types";
3 | import { BookCopy, Database } from "lucide-react";
4 |
5 | export const toolkitGroups: ToolkitGroup[] = [
6 | {
7 | id: ToolkitGroups.Native,
8 | name: "Native Tools",
9 | icon: Logo,
10 | },
11 | {
12 | id: ToolkitGroups.DataSource,
13 | name: "Data Sources",
14 | icon: Database,
15 | },
16 | {
17 | id: ToolkitGroups.KnowledgeBase,
18 | name: "Knowledge Base",
19 | icon: BookCopy,
20 | },
21 | ];
22 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/notion/tools/client.ts:
--------------------------------------------------------------------------------
1 | export {
2 | notionListDatabasesToolConfigClient,
3 | notionQueryDatabaseToolConfigClient,
4 | notionCreateDatabaseToolConfigClient,
5 | } from "./databases/client";
6 |
7 | export {
8 | notionGetPageToolConfigClient,
9 | notionSearchPagesToolConfigClient,
10 | notionCreatePageToolConfigClient,
11 | } from "./pages/client";
12 |
13 | export {
14 | notionGetBlocksToolConfigClient,
15 | notionAppendBlocksToolConfigClient,
16 | } from "./blocks/client";
17 |
18 | export { notionListUsersToolConfigClient } from "./users/client";
19 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/notion/tools/server.ts:
--------------------------------------------------------------------------------
1 | export {
2 | notionListDatabasesToolConfigServer,
3 | notionQueryDatabaseToolConfigServer,
4 | notionCreateDatabaseToolConfigServer,
5 | } from "./databases/server";
6 |
7 | export {
8 | notionGetPageToolConfigServer,
9 | notionSearchPagesToolConfigServer,
10 | notionCreatePageToolConfigServer,
11 | } from "./pages/server";
12 |
13 | export {
14 | notionGetBlocksToolConfigServer,
15 | notionAppendBlocksToolConfigServer,
16 | } from "./blocks/server";
17 |
18 | export { notionListUsersToolConfigServer } from "./users/server";
19 |
--------------------------------------------------------------------------------
/src/lib/utils.ts:
--------------------------------------------------------------------------------
1 | import { clsx, type ClassValue } from "clsx";
2 | import { twMerge } from "tailwind-merge";
3 |
4 | export function cn(...inputs: ClassValue[]) {
5 | return twMerge(clsx(inputs));
6 | }
7 |
8 | export function generateUUID(): string {
9 | return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
10 | const r = (Math.random() * 16) | 0;
11 | const v = c === "x" ? r : (r & 0x3) | 0x8;
12 | return v.toString(16);
13 | });
14 | }
15 |
16 | export function sanitizeText(text: string) {
17 | return text.replace("", "");
18 | }
19 |
--------------------------------------------------------------------------------
/src/ai/language/types.ts:
--------------------------------------------------------------------------------
1 | import type { ProviderMetadata } from "ai";
2 |
3 | export enum LanguageModelCapability {
4 | Vision = "vision",
5 | WebSearch = "web-search",
6 | Reasoning = "reasoning",
7 | Pdf = "pdf",
8 | ToolCalling = "tool-calling",
9 | Free = "free",
10 | }
11 |
12 | export type LanguageModel = {
13 | name: string;
14 | provider: string;
15 | modelId: string;
16 | description?: string;
17 | capabilities?: LanguageModelCapability[];
18 | bestFor?: string[];
19 | contextLength?: number;
20 | isNew?: boolean;
21 | providerOptions?: ProviderMetadata;
22 | };
23 |
--------------------------------------------------------------------------------
/src/contexts/env/index.tsx:
--------------------------------------------------------------------------------
1 | import { env } from "@/env";
2 |
3 | import { AvailableEnvVarsProvider } from "./available-env-vars";
4 |
5 | import { IS_DEVELOPMENT } from "@/lib/constants";
6 |
7 | export const EnvProvider = ({ children }: { children: React.ReactNode }) => {
8 | if (!IS_DEVELOPMENT) {
9 | return children;
10 | }
11 |
12 | return (
13 | [key, Boolean(value)]),
16 | )}
17 | >
18 | {children}
19 |
20 | );
21 | };
22 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/strava/tools/routes/base.ts:
--------------------------------------------------------------------------------
1 | import { z } from "zod";
2 |
3 | import { createBaseTool } from "@/toolkits/create-tool";
4 |
5 | import type { Route } from "strava";
6 |
7 | export const getRoutesBase = createBaseTool({
8 | description: "Get the authenticated athlete's routes (requires Premium)",
9 | inputSchema: z.object({
10 | page: z.number().optional().describe("Page number for pagination"),
11 | per_page: z.number().optional().describe("Number of routes per page"),
12 | }),
13 | outputSchema: z.object({
14 | routes: z.array(z.custom()),
15 | }),
16 | });
17 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/twitter/base.ts:
--------------------------------------------------------------------------------
1 | import type { ToolkitConfig } from "@/toolkits/types";
2 | import { z } from "zod";
3 | import { TwitterTools } from "./tools";
4 | import { getUserProfileTool, getLatestTweetsTool } from "./tools";
5 |
6 | export const twitterParameters = z.object({});
7 |
8 | export const baseTwitterToolkitConfig: ToolkitConfig<
9 | TwitterTools,
10 | typeof twitterParameters.shape
11 | > = {
12 | tools: {
13 | [TwitterTools.GetUserProfile]: getUserProfileTool,
14 | [TwitterTools.GetLatestTweets]: getLatestTweetsTool,
15 | },
16 | parameters: twitterParameters,
17 | };
18 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/twitter/tools/profile/base.ts:
--------------------------------------------------------------------------------
1 | import { z } from "zod";
2 | import { createBaseTool } from "@/toolkits/create-tool";
3 | import type { UserV2Result } from "twitter-api-v2";
4 |
5 | export const getUserProfileTool = createBaseTool({
6 | description: "Get Twitter user profile information by username",
7 | inputSchema: z.object({
8 | username: z
9 | .string()
10 | .describe(
11 | "Twitter username (without @ symbol). Example: 'elonmusk', 'twitter'",
12 | ),
13 | }),
14 | outputSchema: z.object({
15 | user: z.custom(),
16 | }),
17 | });
18 |
--------------------------------------------------------------------------------
/src/app/(general)/page.tsx:
--------------------------------------------------------------------------------
1 | import { Chat } from "./_components/chat";
2 | import LandingPage from "./_components/landing-page";
3 |
4 | import { auth } from "@/server/auth";
5 |
6 | import { generateUUID } from "@/lib/utils";
7 |
8 | export default async function Page() {
9 | const session = await auth();
10 |
11 | if (!session) {
12 | return ;
13 | }
14 |
15 | const id = generateUUID();
16 |
17 | return (
18 |
25 | );
26 | }
27 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/google-calendar/lib/calendar-client.ts:
--------------------------------------------------------------------------------
1 | import { google } from "googleapis";
2 | import type { calendar_v3 } from "googleapis";
3 |
4 | /**
5 | * Creates a Google Calendar client with the provided access token
6 | * @param accessToken - The Google OAuth access token
7 | * @returns A configured Google Calendar client
8 | */
9 | export const createCalendarClient = (
10 | accessToken: string,
11 | ): calendar_v3.Calendar => {
12 | const auth = new google.auth.OAuth2();
13 | auth.setCredentials({ access_token: accessToken });
14 | return google.calendar({ version: "v3", auth });
15 | };
16 |
--------------------------------------------------------------------------------
/src/server/db.ts:
--------------------------------------------------------------------------------
1 | import { PrismaClient } from "@prisma/client";
2 |
3 | import { env } from "@/env";
4 |
5 | const createPrismaClient = () =>
6 | new PrismaClient({
7 | log:
8 | env.NODE_ENV === "development" && env.PRISMA_LOG_QUERIES === "true"
9 | ? ["query", "error", "warn"]
10 | : ["error"],
11 | });
12 |
13 | const globalForPrisma = globalThis as unknown as {
14 | prisma: ReturnType | undefined;
15 | };
16 |
17 | export const db = globalForPrisma.prisma ?? createPrismaClient();
18 |
19 | if (env.NODE_ENV !== "production") globalForPrisma.prisma = db;
20 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/discord/base.ts:
--------------------------------------------------------------------------------
1 | import { z } from "zod";
2 |
3 | import { DiscordTools, listServersTool, getUserInfoTool } from "./tools";
4 |
5 | import type { ToolkitConfig } from "@/toolkits/types";
6 |
7 | export const discordParameters = z.object({
8 | // No parameters needed for user-focused tools
9 | });
10 |
11 | export const baseDiscordToolkitConfig: ToolkitConfig<
12 | DiscordTools,
13 | typeof discordParameters.shape
14 | > = {
15 | tools: {
16 | [DiscordTools.ListServers]: listServersTool,
17 | [DiscordTools.GetUserInfo]: getUserInfoTool,
18 | },
19 | parameters: discordParameters,
20 | };
21 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/notion/lib/title.ts:
--------------------------------------------------------------------------------
1 | import type { PageObjectResponse } from "@notionhq/client/build/src/api-endpoints";
2 |
3 | export const getTitle = (page: PageObjectResponse) => {
4 | if (
5 | "title" in page.properties &&
6 | page.properties.title?.type === "title" &&
7 | page.properties.title.title?.[0]?.plain_text
8 | ) {
9 | return page.properties.title.title[0].plain_text;
10 | }
11 |
12 | const urlTitle =
13 | page.url.split("/").pop()?.split("-").slice(0, -1).join(" ") ?? "";
14 |
15 | if (urlTitle) {
16 | return urlTitle;
17 | }
18 |
19 | return "Untitled Page";
20 | };
21 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/google-calendar/tools/get-event/base.ts:
--------------------------------------------------------------------------------
1 | import { z } from "zod";
2 | import { createBaseTool } from "@/toolkits/create-tool";
3 | import type { calendar_v3 } from "googleapis";
4 |
5 | export const getEventTool = createBaseTool({
6 | description: "Get details of a specific event by ID",
7 | inputSchema: z.object({
8 | calendarId: z
9 | .string()
10 | .describe("The ID of the calendar containing the event"),
11 | eventId: z.string().describe("The ID of the event to retrieve"),
12 | }),
13 | outputSchema: z.object({
14 | event: z.custom(),
15 | }),
16 | });
17 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/video/tools/generate/client.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | import type { baseGenerateTool } from "./base";
4 |
5 | import type { ClientToolConfig } from "@/toolkits/types";
6 |
7 | export const generateToolConfigClient: ClientToolConfig<
8 | typeof baseGenerateTool.inputSchema.shape,
9 | typeof baseGenerateTool.outputSchema.shape
10 | > = {
11 | CallComponent: ({ args }) => {
12 | return {args.prompt};
13 | },
14 | ResultComponent: ({ result }) => {
15 | return ;
16 | },
17 | };
18 |
--------------------------------------------------------------------------------
/src/app/(general)/_components/landing-page/vision/index.tsx:
--------------------------------------------------------------------------------
1 | import { Heading } from "../lib/heading";
2 | import { Section } from "../lib/section";
3 | import { SECTIONS } from "../sections";
4 | import { VisionGraphic } from "./graphic";
5 |
6 | export const VisionSection: React.FC = () => {
7 | return (
8 |
16 | );
17 | };
18 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/google-calendar/tools/client.ts:
--------------------------------------------------------------------------------
1 | export { googleCalendarListCalendarsToolConfigClient } from "./list-calendars/client";
2 | export { googleCalendarGetCalendarToolConfigClient } from "./get-calendar/client";
3 | export { googleCalendarListEventsToolConfigClient } from "./list-events/client";
4 | export { googleCalendarGetEventToolConfigClient } from "./get-event/client";
5 | export { googleCalendarSearchEventsToolConfigClient } from "./search-events/client";
6 | export { googleCalendarCreateEventToolConfigClient } from "./create-event/client";
7 | export { googleCalendarFindAvailabilityToolConfigClient } from "./find-availability/client";
8 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/google-calendar/tools/server.ts:
--------------------------------------------------------------------------------
1 | export { googleCalendarListCalendarsToolConfigServer } from "./list-calendars/server";
2 | export { googleCalendarGetCalendarToolConfigServer } from "./get-calendar/server";
3 | export { googleCalendarListEventsToolConfigServer } from "./list-events/server";
4 | export { googleCalendarGetEventToolConfigServer } from "./get-event/server";
5 | export { googleCalendarSearchEventsToolConfigServer } from "./search-events/server";
6 | export { googleCalendarCreateEventToolConfigServer } from "./create-event/server";
7 | export { googleCalendarFindAvailabilityToolConfigServer } from "./find-availability/server";
8 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/spotify/base.ts:
--------------------------------------------------------------------------------
1 | // src/toolkits/toolkits/spotify/base.ts
2 | import type { ToolkitConfig } from "@/toolkits/types";
3 | import { getTracksBase, SpotifyTools } from "./tools";
4 | import { z } from "zod";
5 | import { getPlaylistsBase } from "./tools/playlists/base";
6 |
7 | export const spotifyParameters = z.object({});
8 |
9 | export const baseSpotifyToolkitConfig: ToolkitConfig<
10 | SpotifyTools,
11 | typeof spotifyParameters.shape
12 | > = {
13 | tools: {
14 | [SpotifyTools.GetPlaylists]: getPlaylistsBase,
15 | [SpotifyTools.GetTracks]: getTracksBase,
16 | },
17 | parameters: spotifyParameters,
18 | };
19 |
--------------------------------------------------------------------------------
/setup/steps/2_dependencies.ts:
--------------------------------------------------------------------------------
1 | import { execSync } from "child_process";
2 |
3 | import { logInfo, logSuccess, logError, getPackageManager } from "../utils";
4 |
5 | // Install dependencies
6 | export function installDependencies(): void {
7 | try {
8 | // Check for package manager
9 | const packageManager = getPackageManager();
10 |
11 | logInfo(`Using ${packageManager} as package manager`);
12 |
13 | execSync(`${packageManager} install`, { stdio: "ignore" });
14 | logSuccess("Dependencies installed successfully");
15 | } catch (error) {
16 | logError("Failed to install dependencies");
17 | throw error;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/app/_components/navbar/account-button/index.tsx:
--------------------------------------------------------------------------------
1 | import { Unauthenticated } from "./unauthenticated";
2 | import { Authenticated } from "./authenticated";
3 |
4 | import { auth } from "@/server/auth";
5 | import { providers } from "@/server/auth/providers";
6 |
7 | export const AccountButton = async () => {
8 | const session = await auth();
9 |
10 | if (!session) {
11 | return (
12 | ({
14 | name: provider.name,
15 | id: provider.id,
16 | }))}
17 | />
18 | );
19 | }
20 |
21 | return ;
22 | };
23 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/mem0/base.ts:
--------------------------------------------------------------------------------
1 | import type { ToolkitConfig } from "@/toolkits/types";
2 | import { baseAddMemoryTool } from "./tools/add_memory/base";
3 | import { baseSearchMemoriesTool } from "./tools/search_memories/base";
4 | import { Mem0Tools } from "./tools/tools";
5 | import { z } from "zod";
6 |
7 | export const mem0Parameters = z.object({});
8 |
9 | export const baseMem0ToolkitConfig: ToolkitConfig<
10 | Mem0Tools,
11 | typeof mem0Parameters.shape
12 | > = {
13 | tools: {
14 | [Mem0Tools.AddMemory]: baseAddMemoryTool,
15 | [Mem0Tools.SearchMemories]: baseSearchMemoriesTool,
16 | },
17 | parameters: mem0Parameters,
18 | };
19 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/strava/tools/activity-details/base.ts:
--------------------------------------------------------------------------------
1 | import { z } from "zod";
2 |
3 | import { createBaseTool } from "@/toolkits/create-tool";
4 |
5 | import type { DetailedActivity } from "strava";
6 |
7 | export const getActivityDetailsBase = createBaseTool({
8 | description: "Get detailed information about a specific activity",
9 | inputSchema: z.object({
10 | id: z.number().describe("The activity ID"),
11 | include_all_efforts: z
12 | .boolean()
13 | .optional()
14 | .describe("Include all segment efforts"),
15 | }),
16 | outputSchema: z.object({
17 | activity: z.custom(),
18 | }),
19 | });
20 |
--------------------------------------------------------------------------------
/src/ai/language/generate.ts:
--------------------------------------------------------------------------------
1 | import { generateText as generateTextAi, streamText as streamTextAi } from "ai";
2 |
3 | import { openrouter } from "./provider";
4 |
5 | export const generateText = (
6 | model: `${string}/${string}`,
7 | params: Omit[0], "model">,
8 | ) => {
9 | return generateTextAi({
10 | model: openrouter(model),
11 | ...params,
12 | });
13 | };
14 |
15 | export const streamText = (
16 | model: `${string}/${string}`,
17 | params: Omit[0], "model">,
18 | ) => {
19 | return streamTextAi({
20 | model: openrouter(model),
21 | ...params,
22 | });
23 | };
24 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/image/tools/generate/base.ts:
--------------------------------------------------------------------------------
1 | import { z } from "zod";
2 | import { createBaseTool } from "@/toolkits/create-tool";
3 |
4 | const inputSchema = z.object({
5 | prompt: z.string().min(1).max(250).describe("The image generation prompt"),
6 | });
7 |
8 | const outputSchema = z.object({
9 | url: z.string().describe("The URL of the generated image"),
10 | });
11 |
12 | export const baseGenerateTool = createBaseTool({
13 | description: "Generate an image",
14 | inputSchema,
15 | outputSchema,
16 | });
17 |
18 | export type GenerateToolArgs = z.infer;
19 | export type GenerateToolResult = z.infer;
20 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/google-drive/base.ts:
--------------------------------------------------------------------------------
1 | import type { ToolkitConfig } from "@/toolkits/types";
2 | import { z } from "zod";
3 | import { GoogleDriveTools } from "./tools";
4 | import { searchFilesTool } from "./tools/search-files/base";
5 | import { readFileTool } from "./tools/read-file/base";
6 |
7 | export const googleDriveParameters = z.object({});
8 |
9 | export const baseGoogleDriveToolkitConfig: ToolkitConfig<
10 | GoogleDriveTools,
11 | typeof googleDriveParameters.shape
12 | > = {
13 | tools: {
14 | [GoogleDriveTools.SearchFiles]: searchFilesTool,
15 | [GoogleDriveTools.ReadFile]: readFileTool,
16 | },
17 | parameters: googleDriveParameters,
18 | };
19 |
--------------------------------------------------------------------------------
/setup/types.ts:
--------------------------------------------------------------------------------
1 | // Types for the setup system
2 |
3 | export type ColorKey =
4 | | "reset"
5 | | "bright"
6 | | "red"
7 | | "green"
8 | | "yellow"
9 | | "blue"
10 | | "magenta"
11 | | "cyan";
12 |
13 | export interface SetupConfig {
14 | useDocker: boolean;
15 | useDockerCompose: boolean;
16 | setupRedis: boolean;
17 | configureApiKeys: boolean;
18 | startDevServer: boolean;
19 | }
20 |
21 | export interface ServiceConfig {
22 | name: string;
23 | url: string;
24 | description: string;
25 | required: boolean;
26 | }
27 |
28 | export interface SetupStep {
29 | name: string;
30 | description: string;
31 | execute: () => Promise;
32 | }
33 |
--------------------------------------------------------------------------------
/src/app/(general)/_components/landing-page/workbenches/index.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | import { Section } from "../lib/section";
4 | import { Heading } from "../lib/heading";
5 |
6 | import { WorkbenchForm } from "./workbench-form";
7 |
8 | import { SECTIONS } from "../sections";
9 |
10 | export const WorkbenchSection: React.FC = () => {
11 | return (
12 |
19 | );
20 | };
21 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/video/server.ts:
--------------------------------------------------------------------------------
1 | import { createServerToolkit } from "@/toolkits/create-toolkit";
2 |
3 | import { baseVideoToolkitConfig } from "./base";
4 | import { VideoTools } from "./tools";
5 |
6 | import { generateToolConfigServer } from "./tools/generate/server";
7 |
8 | export const videoToolkitServer = createServerToolkit(
9 | baseVideoToolkitConfig,
10 | `You have access to the comprehensive video toolkit for video generation. This toolkit provides:
11 |
12 | - **Video Generation** - Generate videos with AI`,
13 | async (parameters) => {
14 | return {
15 | [VideoTools.Generate]: generateToolConfigServer(parameters),
16 | };
17 | },
18 | );
19 |
--------------------------------------------------------------------------------
/prisma/migrations/20250721200114_update_tool_schema/migration.sql:
--------------------------------------------------------------------------------
1 | /*
2 | Warnings:
3 |
4 | - The primary key for the `Tool` table will be changed. If it partially fails, the table could be left without primary key constraint.
5 | - You are about to drop the column `name` on the `Tool` table. All the data in the column will be lost.
6 | - You are about to drop the column `name` on the `Toolkit` table. All the data in the column will be lost.
7 |
8 | */
9 | -- AlterTable
10 | ALTER TABLE "Tool" DROP CONSTRAINT "Tool_pkey",
11 | DROP COLUMN "name",
12 | ADD CONSTRAINT "Tool_pkey" PRIMARY KEY ("id", "toolkitId");
13 |
14 | -- AlterTable
15 | ALTER TABLE "Toolkit" DROP COLUMN "name";
16 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/e2b/server.ts:
--------------------------------------------------------------------------------
1 | import { createServerToolkit } from "@/toolkits/create-toolkit";
2 | import { baseE2BToolkitConfig } from "./base";
3 | import { e2bRunCodeToolConfigServer } from "./tools/run_code/server";
4 | import { E2BTools } from "./tools/tools";
5 |
6 | export const e2bToolkitServer = createServerToolkit(
7 | baseE2BToolkitConfig,
8 | `You have access to the E2B toolkit for secure code execution and development environments. This toolkit provides:
9 |
10 | - **Run Code**: Execute Python code in isolated, secure cloud environments.`,
11 | async () => {
12 | return {
13 | [E2BTools.RunCode]: e2bRunCodeToolConfigServer(),
14 | };
15 | },
16 | );
17 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/mem0/components/tool-call-display.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { type LucideIcon } from "lucide-react";
3 | import { HStack } from "@/components/ui/stack";
4 |
5 | interface ToolCallDisplayProps {
6 | icon: LucideIcon;
7 | label: string;
8 | value: string;
9 | }
10 |
11 | export function ToolCallDisplay({
12 | icon: Icon,
13 | label,
14 | value,
15 | }: ToolCallDisplayProps) {
16 | return (
17 |
18 |
19 |
20 | {label}: {value}
21 |
22 |
23 | );
24 | }
25 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/strava/tools/profile/server.ts:
--------------------------------------------------------------------------------
1 | import type { ServerToolConfig } from "@/toolkits/types";
2 | import type { Strava } from "strava";
3 | import type { getAthleteBase } from "./base";
4 |
5 | export const getAthleteProfileToolConfigServer = (
6 | strava: Strava,
7 | ): ServerToolConfig<
8 | typeof getAthleteBase.inputSchema.shape,
9 | typeof getAthleteBase.outputSchema.shape
10 | > => {
11 | return {
12 | callback: async () => {
13 | const athlete = await strava.athletes.getLoggedInAthlete();
14 |
15 | return {
16 | athlete,
17 | };
18 | },
19 | message: "Successfully retrieved athlete profile from Strava.",
20 | };
21 | };
22 |
--------------------------------------------------------------------------------
/src/components/ui/code/shared.ts:
--------------------------------------------------------------------------------
1 | import { Fragment } from "react";
2 | import { jsx, jsxs } from "react/jsx-runtime";
3 |
4 | import { toJsxRuntime } from "hast-util-to-jsx-runtime";
5 |
6 | import { codeToHast } from "./shiki.bundle";
7 |
8 | import type { JSX } from "react";
9 | import type { BundledLanguage } from "./shiki.bundle.ts";
10 |
11 | export async function highlight(code: string, lang: BundledLanguage) {
12 | const out = await codeToHast(code, {
13 | lang,
14 | themes: {
15 | light: "github-light",
16 | dark: "github-dark",
17 | },
18 | });
19 |
20 | return toJsxRuntime(out, {
21 | Fragment,
22 | jsx,
23 | jsxs,
24 | }) as JSX.Element;
25 | }
26 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/google-calendar/tools/create-event/base.ts:
--------------------------------------------------------------------------------
1 | import { z } from "zod";
2 | import { createBaseTool } from "@/toolkits/create-tool";
3 | import type { calendar_v3 } from "googleapis";
4 |
5 | export const createEventTool = createBaseTool({
6 | description: "Create a new event in a Google Calendar",
7 | inputSchema: z
8 | .object({
9 | title: z.string().describe("Event title"),
10 | startDateTime: z.string().describe("Start time (RFC3339 timestamp)"),
11 | endDateTime: z.string().describe("End time (RFC3339 timestamp)"),
12 | })
13 | .required(),
14 | outputSchema: z.object({
15 | event: z.custom(),
16 | }),
17 | });
18 |
--------------------------------------------------------------------------------
/src/components/ui/sonner.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { useTheme } from "next-themes";
4 | import { Toaster as Sonner, type ToasterProps } from "sonner";
5 |
6 | const Toaster = ({ ...props }: ToasterProps) => {
7 | const { theme = "system" } = useTheme();
8 |
9 | return (
10 |
22 | );
23 | };
24 |
25 | export { Toaster };
26 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/discord/tools/get-user-info/server.ts:
--------------------------------------------------------------------------------
1 | import { Routes } from "discord-api-types/v10";
2 |
3 | import type { getUserInfoTool } from "./base";
4 | import type { ServerToolConfig } from "@/toolkits/types";
5 | import type { APIUser } from "discord-api-types/v10";
6 | import type { REST } from "@discordjs/rest";
7 |
8 | export const getUserInfoToolConfigServer = (
9 | rest: REST,
10 | ): ServerToolConfig<
11 | typeof getUserInfoTool.inputSchema.shape,
12 | typeof getUserInfoTool.outputSchema.shape
13 | > => {
14 | return {
15 | callback: async () => {
16 | return {
17 | user: (await rest.get(Routes.user("@me"))) as APIUser,
18 | };
19 | },
20 | };
21 | };
22 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/strava/tools/zones/server.ts:
--------------------------------------------------------------------------------
1 | import type { Strava } from "strava";
2 |
3 | import type { getAthleteZonesBase } from "./base";
4 |
5 | import type { ServerToolConfig } from "@/toolkits/types";
6 |
7 | export const getAthleteZonesToolConfigServer = (
8 | strava: Strava,
9 | ): ServerToolConfig<
10 | typeof getAthleteZonesBase.inputSchema.shape,
11 | typeof getAthleteZonesBase.outputSchema.shape
12 | > => {
13 | return {
14 | callback: async () => {
15 | const zones = await strava.athletes.getLoggedInAthleteZones();
16 |
17 | return {
18 | zones,
19 | };
20 | },
21 | message: "Successfully retrieved athlete zones from Strava.",
22 | };
23 | };
24 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/discord/tools/list-servers/server.ts:
--------------------------------------------------------------------------------
1 | import { Routes } from "discord-api-types/v10";
2 |
3 | import type { listServersTool } from "./base";
4 | import type { ServerToolConfig } from "@/toolkits/types";
5 | import type { APIGuild } from "discord-api-types/v10";
6 | import type { REST } from "@discordjs/rest";
7 |
8 | export const listServersToolConfigServer = (
9 | rest: REST,
10 | ): ServerToolConfig<
11 | typeof listServersTool.inputSchema.shape,
12 | typeof listServersTool.outputSchema.shape
13 | > => {
14 | return {
15 | callback: async () => {
16 | return {
17 | servers: (await rest.get(Routes.userGuilds())) as APIGuild[],
18 | };
19 | },
20 | };
21 | };
22 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/mem0/tools/add_memory/base.ts:
--------------------------------------------------------------------------------
1 | import { z } from "zod";
2 | import { createBaseTool } from "@/toolkits/create-tool";
3 |
4 | export const baseAddMemoryTool = createBaseTool({
5 | description:
6 | "Add a new memory. This method is called every time the user informs anything about themselves, their preferences, or anything that has any relevant information which can be useful in the future conversation. This can also be called when the user asks you to remember something.",
7 | inputSchema: z.object({
8 | content: z.string().describe("The content to store in memory"),
9 | }),
10 | outputSchema: z.object({
11 | success: z.boolean(),
12 | content: z.string(),
13 | }),
14 | });
15 |
--------------------------------------------------------------------------------
/src/components/ui/merit-logo.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | import Image from "next/image";
4 | import { cn } from "@/lib/utils";
5 |
6 | interface Props {
7 | className?: string;
8 | }
9 |
10 | export const MeritLogo: React.FC = ({ className }) => {
11 | return (
12 | <>
13 |
20 |
27 | >
28 | );
29 | };
30 |
--------------------------------------------------------------------------------
/src/lib/fetch.ts:
--------------------------------------------------------------------------------
1 | import { ChatSDKError, type ErrorCode } from "@/lib/errors";
2 |
3 | export async function fetchWithErrorHandlers(
4 | input: RequestInfo | URL,
5 | init?: RequestInit,
6 | ) {
7 | try {
8 | const response = await fetch(input, init);
9 |
10 | if (!response.ok) {
11 | const { code, cause } = (await response.json()) as {
12 | code: ErrorCode;
13 | cause: string;
14 | };
15 | throw new ChatSDKError(code, cause);
16 | }
17 |
18 | return response;
19 | } catch (error: unknown) {
20 | if (typeof navigator !== "undefined" && !navigator.onLine) {
21 | throw new ChatSDKError("offline:chat");
22 | }
23 |
24 | throw error;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/server/api/routers/index.ts:
--------------------------------------------------------------------------------
1 | export { chatsRouter } from "./chats";
2 | export { messagesRouter } from "./messages";
3 | export { streamsRouter } from "./streams";
4 | export { filesRouter } from "./files";
5 | export { usersRouter } from "./users";
6 | export { accountsRouter } from "./accounts";
7 | export { imagesRouter } from "./images";
8 | export { memoriesRouter } from "./memories";
9 | export { featuresRouter } from "./features";
10 | export { workbenchesRouter } from "./workbenches";
11 | export { toolkitsRouter } from "./toolkits";
12 | export { toolsRouter } from "./tools";
13 | export { creditsRouter } from "./credits";
14 | export { videosRouter } from "./videos";
15 | export { syncRouter } from "./sync";
16 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/image/tools/generate/client.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | import Image from "next/image";
4 |
5 | import type { baseGenerateTool } from "./base";
6 |
7 | import type { ClientToolConfig } from "@/toolkits/types";
8 |
9 | export const generateToolConfigClient: ClientToolConfig<
10 | typeof baseGenerateTool.inputSchema.shape,
11 | typeof baseGenerateTool.outputSchema.shape
12 | > = {
13 | CallComponent: ({ args }) => {
14 | return {args.prompt};
15 | },
16 | ResultComponent: ({ result }) => {
17 | return (
18 |
19 | );
20 | },
21 | };
22 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/notion/tools/index.ts:
--------------------------------------------------------------------------------
1 | export enum NotionTools {
2 | ListDatabases = "list-databases",
3 | QueryDatabase = "query-database",
4 | CreateDatabase = "create-database",
5 | GetPage = "get-page",
6 | SearchPages = "search-pages",
7 | CreatePage = "create-page",
8 | GetBlocks = "get-blocks",
9 | AppendBlocks = "append-blocks",
10 | ListUsers = "list-users",
11 | }
12 |
13 | export {
14 | listDatabasesTool,
15 | queryDatabaseTool,
16 | createDatabaseTool,
17 | } from "./databases/base";
18 | export { getPageTool, searchPagesTool, createPageTool } from "./pages/base";
19 | export { getBlocksTool, appendBlocksTool } from "./blocks/base";
20 | export { listUsersTool } from "./users/base";
21 |
--------------------------------------------------------------------------------
/next.config.js:
--------------------------------------------------------------------------------
1 | import "./src/env.js";
2 |
3 | /** @type {import("next").NextConfig} */
4 | const config = {
5 | images: {
6 | remotePatterns:
7 | process.env.NODE_ENV === "development"
8 | ? [
9 | {
10 | protocol: "http",
11 | hostname: "localhost",
12 | port: "6969",
13 | },
14 | ]
15 | : [
16 | {
17 | protocol: "https",
18 | hostname: "3kjwme0xuhfnyrkn.public.blob.vercel-storage.com",
19 | },
20 | ],
21 | },
22 | experimental: {
23 | authInterrupts: true,
24 | },
25 | serverExternalPackages: ["twitter-api-v2"],
26 | };
27 |
28 | export default config;
29 |
--------------------------------------------------------------------------------
/src/ai/image/models/fireworks.ts:
--------------------------------------------------------------------------------
1 | import type { ImageModel } from "../types";
2 |
3 | const fireworksImageModelsData: Omit[] = [
4 | {
5 | name: "Playground v2.5 1024",
6 | modelId: "accounts/fireworks/models/playground-v2-5-1024px-aesthetic",
7 | },
8 | {
9 | name: "Segmind Stable Diffusion 1B",
10 | modelId: "accounts/fireworks/models/SSD-1B",
11 | },
12 | {
13 | name: "Japanese Stable Diffusion XL",
14 | modelId: "accounts/fireworks/models/japanese-stable-diffusion-xl",
15 | },
16 | ];
17 |
18 | export const fireworksImageModels: ImageModel[] = fireworksImageModelsData.map(
19 | (model) => ({
20 | ...model,
21 | provider: "fireworks",
22 | }),
23 | );
24 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/google-calendar/tools/get-calendar/server.ts:
--------------------------------------------------------------------------------
1 | import { type getCalendarTool } from "./base";
2 | import type { ServerToolConfig } from "@/toolkits/types";
3 | import type { calendar_v3 } from "googleapis";
4 |
5 | export const googleCalendarGetCalendarToolConfigServer = (
6 | calendar: calendar_v3.Calendar,
7 | ): ServerToolConfig<
8 | typeof getCalendarTool.inputSchema.shape,
9 | typeof getCalendarTool.outputSchema.shape
10 | > => {
11 | return {
12 | callback: async ({ calendarId }) => {
13 | const response = await calendar.calendars.get({
14 | calendarId,
15 | });
16 |
17 | return {
18 | calendar: response.data,
19 | };
20 | },
21 | };
22 | };
23 |
--------------------------------------------------------------------------------
/src/components/ui/logo/static.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | import Image from "next/image";
4 |
5 | import { cn } from "@/lib/utils";
6 |
7 | interface Props {
8 | className?: string;
9 | }
10 |
11 | export const Logo: React.FC = ({ className }) => {
12 | return (
13 | <>
14 |
21 |
28 | >
29 | );
30 | };
31 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/strava/tools/segment/server.ts:
--------------------------------------------------------------------------------
1 | import type { Strava } from "strava";
2 |
3 | import type { ServerToolConfig } from "@/toolkits/types";
4 |
5 | import type { getSegmentDetailsBase } from "./base";
6 |
7 | export const getSegmentDetailsToolConfigServer = (
8 | strava: Strava,
9 | ): ServerToolConfig<
10 | typeof getSegmentDetailsBase.inputSchema.shape,
11 | typeof getSegmentDetailsBase.outputSchema.shape
12 | > => {
13 | return {
14 | callback: async ({ id }) => {
15 | const segment = await strava.segments.getSegmentById({ id });
16 |
17 | return {
18 | segment,
19 | };
20 | },
21 | message: "Successfully retrieved segment details from Strava.",
22 | };
23 | };
24 |
--------------------------------------------------------------------------------
/src/components/ui/stack.tsx:
--------------------------------------------------------------------------------
1 | import { cn } from "@/lib/utils";
2 | import React from "react";
3 |
4 | export const HStack: React.FC> = ({
5 | children,
6 | className,
7 | ...props
8 | }) => {
9 | return (
10 |
14 | {children}
15 |
16 | );
17 | };
18 |
19 | export const VStack: React.FC> = ({
20 | children,
21 | className,
22 | ...props
23 | }) => {
24 | return (
25 |
29 | {children}
30 |
31 | );
32 | };
33 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/google-calendar/tools/get-event/server.ts:
--------------------------------------------------------------------------------
1 | import { type getEventTool } from "./base";
2 | import type { ServerToolConfig } from "@/toolkits/types";
3 | import type { calendar_v3 } from "googleapis";
4 |
5 | export const googleCalendarGetEventToolConfigServer = (
6 | calendar: calendar_v3.Calendar,
7 | ): ServerToolConfig<
8 | typeof getEventTool.inputSchema.shape,
9 | typeof getEventTool.outputSchema.shape
10 | > => {
11 | return {
12 | callback: async ({ calendarId, eventId }) => {
13 | const response = await calendar.events.get({
14 | calendarId,
15 | eventId,
16 | });
17 |
18 | return {
19 | event: response.data,
20 | };
21 | },
22 | };
23 | };
24 |
--------------------------------------------------------------------------------
/src/app/(general)/workbench/[id]/edit/page.tsx:
--------------------------------------------------------------------------------
1 | import { notFound } from "next/navigation";
2 | import { api } from "@/trpc/server";
3 | import { EditWorkbenchForm } from "./_components/edit-workbench-form";
4 |
5 | interface EditWorkbenchPageProps {
6 | params: Promise<{ id: string }>;
7 | }
8 |
9 | export default async function EditWorkbenchPage({
10 | params,
11 | }: EditWorkbenchPageProps) {
12 | const { id } = await params;
13 |
14 | try {
15 | const workbench = await api.workbenches.getWorkbench(id);
16 |
17 | if (!workbench) {
18 | notFound();
19 | }
20 |
21 | return ;
22 | } catch (error) {
23 | console.error(error);
24 | notFound();
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/app/(general)/layout.tsx:
--------------------------------------------------------------------------------
1 | import { SidebarInset, SidebarProvider } from "@/components/ui/sidebar";
2 |
3 | import { Navbar } from "../_components/navbar";
4 |
5 | import { AppSidebar } from "./_components/sidebar";
6 | import { InstallPromptProvider } from "@/app/(general)/_contexts/install-prompt-context";
7 |
8 | export default async function GeneralLayout({
9 | children,
10 | }: Readonly<{ children: React.ReactNode }>) {
11 | return (
12 |
13 |
14 |
15 |
16 |
17 | {children}
18 |
19 |
20 |
21 | );
22 | }
23 |
--------------------------------------------------------------------------------
/src/app/(general)/login/page.tsx:
--------------------------------------------------------------------------------
1 | import { providers } from "@/server/auth/providers";
2 |
3 | import { LoginForm } from "./login-form";
4 | import { auth } from "@/server/auth";
5 | import { redirect } from "next/navigation";
6 |
7 | export default async function LoginPage() {
8 | const session = await auth();
9 |
10 | if (session) {
11 | redirect("/");
12 | }
13 |
14 | const mappedProviders = providers.map((provider) => ({
15 | name: provider.name,
16 | id: provider.id,
17 | }));
18 |
19 | return (
20 |
25 | );
26 | }
27 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/github/base.ts:
--------------------------------------------------------------------------------
1 | import type { ToolkitConfig } from "@/toolkits/types";
2 | import { z } from "zod";
3 | import { GithubTools } from "./tools";
4 | import {
5 | searchRepositoriesTool,
6 | repoInfoTool,
7 | searchCodeTool,
8 | searchUsersTool,
9 | } from "./tools";
10 |
11 | export const githubParameters = z.object({});
12 |
13 | export const baseGithubToolkitConfig: ToolkitConfig<
14 | GithubTools,
15 | typeof githubParameters.shape
16 | > = {
17 | tools: {
18 | [GithubTools.SearchRepos]: searchRepositoriesTool,
19 | [GithubTools.RepoInfo]: repoInfoTool,
20 | [GithubTools.SearchCode]: searchCodeTool,
21 | [GithubTools.SearchUsers]: searchUsersTool,
22 | },
23 | parameters: githubParameters,
24 | };
25 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/e2b/tools/run_code/base.ts:
--------------------------------------------------------------------------------
1 | import { z } from "zod";
2 | import { createBaseTool } from "@/toolkits/create-tool";
3 |
4 | import type { Result, Logs } from "@e2b/code-interpreter";
5 |
6 | export const baseRunCodeTool = createBaseTool({
7 | description:
8 | "Run Python code in a secure sandbox environment using E2B. Supports Jupyter Notebook syntax and returns execution results and logs.",
9 | inputSchema: z.object({
10 | code: z.string().describe("The Python code to execute in the sandbox"),
11 | }),
12 | outputSchema: z.object({
13 | results: z
14 | .array(z.custom())
15 | .describe("The execution results from running the code"),
16 | logs: z.custom().describe("Execution logs"),
17 | }),
18 | });
19 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/strava/tools/explore-segments/base.ts:
--------------------------------------------------------------------------------
1 | import { z } from "zod";
2 |
3 | import { createBaseTool } from "@/toolkits/create-tool";
4 |
5 | import type { DetailedSegment } from "strava";
6 |
7 | export const exploreSegmentsBase = createBaseTool({
8 | description: "Search for segments within geographical bounds",
9 | inputSchema: z.object({
10 | bounds: z
11 | .string()
12 | .describe(
13 | "Comma-delimited list of lat/lng bounds: sw_lat,sw_lng,ne_lat,ne_lng",
14 | ),
15 | activity_type: z
16 | .enum(["running", "riding"])
17 | .optional()
18 | .describe("Filter by activity type"),
19 | }),
20 | outputSchema: z.object({
21 | segments: z.array(z.custom()),
22 | }),
23 | });
24 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/google-calendar/tools/index.ts:
--------------------------------------------------------------------------------
1 | export enum GoogleCalendarTools {
2 | ListCalendars = "list-calendars",
3 | GetCalendar = "get-calendar",
4 | ListEvents = "list-events",
5 | GetEvent = "get-event",
6 | SearchEvents = "search-events",
7 | CreateEvent = "create-event",
8 | FindAvailability = "find-availability",
9 | }
10 |
11 | export { listCalendarsTool } from "./list-calendars/base";
12 | export { getCalendarTool } from "./get-calendar/base";
13 | export { listEventsTool } from "./list-events/base";
14 | export { getEventTool } from "./get-event/base";
15 | export { searchEventsTool } from "./search-events/base";
16 | export { createEventTool } from "./create-event/base";
17 | export { findAvailabilityTool } from "./find-availability/base";
18 |
--------------------------------------------------------------------------------
/src/ai/language/models/all.ts:
--------------------------------------------------------------------------------
1 | import { openAiLanguageModels } from "./openai";
2 | import { xaiLanguageModels } from "./xai";
3 | import { perplexityModels } from "./perplexity";
4 | import { googleModels } from "./google";
5 | import { anthropicModels } from "./anthropic";
6 | import { llamaModels } from "./llama";
7 | import { qwenModels } from "./qwen";
8 | import { deepseekModels } from "./deepseek";
9 | import { openRouterModels } from "./openrouter";
10 |
11 | export const allLanguageModels = [
12 | ...openRouterModels, // Add at the top to give it priority
13 | ...anthropicModels,
14 | ...googleModels,
15 | ...openAiLanguageModels,
16 | ...xaiLanguageModels,
17 | ...perplexityModels,
18 | ...llamaModels,
19 | ...qwenModels,
20 | ...deepseekModels,
21 | ];
22 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/exa/tools/crawling/base.ts:
--------------------------------------------------------------------------------
1 | import { z } from "zod";
2 | import { createBaseTool } from "@/toolkits/create-tool";
3 |
4 | export const baseCrawlingTool = createBaseTool({
5 | description: "Extract content from specific URLs",
6 | inputSchema: z.object({
7 | urls: z.array(z.string()),
8 | }),
9 | outputSchema: z.object({
10 | results: z.array(
11 | z.object({
12 | title: z.string().nullable(),
13 | url: z.string().url(),
14 | content: z.string(),
15 | publishedDate: z.string().optional(),
16 | image: z.string().optional(),
17 | favicon: z.string().optional(),
18 | score: z.number().optional(),
19 | author: z.string().optional(),
20 | }),
21 | ),
22 | }),
23 | });
24 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/spotify/components/tool-call-display.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import type { LucideIcon } from "lucide-react";
3 |
4 | interface ToolCallDisplayProps {
5 | icon: LucideIcon;
6 | label: string;
7 | value: string;
8 | }
9 |
10 | export const ToolCallDisplay: React.FC = ({
11 | icon: Icon,
12 | label,
13 | value,
14 | }) => {
15 | return (
16 |
17 |
18 |
19 |
{label}
20 |
{value}
21 |
22 |
23 | );
24 | };
25 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/strava/tools/stats/server.ts:
--------------------------------------------------------------------------------
1 | import type { Strava } from "strava";
2 |
3 | import type { ServerToolConfig } from "@/toolkits/types";
4 |
5 | import type { getAthleteStatsBase } from "./base";
6 |
7 | export const getAthleteStatsToolConfigServer = (
8 | strava: Strava,
9 | ): ServerToolConfig<
10 | typeof getAthleteStatsBase.inputSchema.shape,
11 | typeof getAthleteStatsBase.outputSchema.shape
12 | > => {
13 | return {
14 | callback: async () => {
15 | const { id } = await strava.athletes.getLoggedInAthlete();
16 |
17 | const stats = await strava.athletes.getStats({ id });
18 |
19 | return {
20 | stats,
21 | };
22 | },
23 | message: "Successfully retrieved athlete statistics from Strava.",
24 | };
25 | };
26 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/exa/tools/search/base.ts:
--------------------------------------------------------------------------------
1 | import { z } from "zod";
2 | import { createBaseTool } from "@/toolkits/create-tool";
3 |
4 | export const baseSearchTool = createBaseTool({
5 | description: "Search the web for up-to-date information",
6 | inputSchema: z.object({
7 | query: z.string().min(1).max(100),
8 | }),
9 | outputSchema: z.object({
10 | results: z.array(
11 | z.object({
12 | title: z.string().nullable(),
13 | url: z.string().url(),
14 | content: z.string(),
15 | publishedDate: z.string().optional(),
16 | image: z.string().optional(),
17 | favicon: z.string().optional(),
18 | score: z.number().optional(),
19 | author: z.string().optional(),
20 | }),
21 | ),
22 | }),
23 | });
24 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/exa/tools/competitor_finder/base.ts:
--------------------------------------------------------------------------------
1 | import { z } from "zod";
2 | import { createBaseTool } from "@/toolkits/create-tool";
3 |
4 | export const baseCompetitorFinderTool = createBaseTool({
5 | description: "Find competitors of a company",
6 | inputSchema: z.object({
7 | company: z.string().min(1).max(100),
8 | }),
9 | outputSchema: z.object({
10 | results: z.array(
11 | z.object({
12 | title: z.string().nullable(),
13 | url: z.string().url(),
14 | content: z.string(),
15 | publishedDate: z.string().optional(),
16 | image: z.string().optional(),
17 | favicon: z.string().optional(),
18 | score: z.number().optional(),
19 | author: z.string().optional(),
20 | }),
21 | ),
22 | }),
23 | });
24 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/exa/tools/github_search/base.ts:
--------------------------------------------------------------------------------
1 | import { z } from "zod";
2 | import { createBaseTool } from "@/toolkits/create-tool";
3 |
4 | export const baseGithubSearchTool = createBaseTool({
5 | description: "Search GitHub repositories and accounts",
6 | inputSchema: z.object({
7 | query: z.string().min(1).max(100),
8 | }),
9 | outputSchema: z.object({
10 | results: z.array(
11 | z.object({
12 | title: z.string().nullable(),
13 | url: z.string().url(),
14 | content: z.string(),
15 | publishedDate: z.string().optional(),
16 | image: z.string().optional(),
17 | favicon: z.string().optional(),
18 | score: z.number().optional(),
19 | author: z.string().optional(),
20 | }),
21 | ),
22 | }),
23 | });
24 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/exa/tools/linkedin_search/base.ts:
--------------------------------------------------------------------------------
1 | import { z } from "zod";
2 | import { createBaseTool } from "@/toolkits/create-tool";
3 |
4 | export const baseLinkedinSearchTool = createBaseTool({
5 | description: "Search LinkedIn for companies and people",
6 | inputSchema: z.object({
7 | query: z.string().min(1).max(100),
8 | }),
9 | outputSchema: z.object({
10 | results: z.array(
11 | z.object({
12 | title: z.string().nullable(),
13 | url: z.string().url(),
14 | content: z.string(),
15 | publishedDate: z.string().optional(),
16 | image: z.string().optional(),
17 | favicon: z.string().optional(),
18 | score: z.number().optional(),
19 | author: z.string().optional(),
20 | }),
21 | ),
22 | }),
23 | });
24 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/exa/tools/wikipedia_search/base.ts:
--------------------------------------------------------------------------------
1 | import { z } from "zod";
2 | import { createBaseTool } from "@/toolkits/create-tool";
3 |
4 | export const baseWikipediaSearchTool = createBaseTool({
5 | description: "Search Wikipedia articles on specific topics",
6 | inputSchema: z.object({
7 | query: z.string().min(1).max(100),
8 | }),
9 | outputSchema: z.object({
10 | results: z.array(
11 | z.object({
12 | title: z.string().nullable(),
13 | url: z.string().url(),
14 | content: z.string(),
15 | publishedDate: z.string().optional(),
16 | image: z.string().optional(),
17 | favicon: z.string().optional(),
18 | score: z.number().optional(),
19 | author: z.string().optional(),
20 | }),
21 | ),
22 | }),
23 | });
24 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/notion/tools/users/base.ts:
--------------------------------------------------------------------------------
1 | import { z } from "zod";
2 | import { createBaseTool } from "@/toolkits/create-tool";
3 | import type { UserObjectResponse } from "@notionhq/client/build/src/api-endpoints";
4 |
5 | export const listUsersTool = createBaseTool({
6 | description: "List all users in the workspace",
7 | inputSchema: z.object({
8 | start_cursor: z
9 | .string()
10 | .describe("Pagination cursor to start from (blank for first page)"),
11 | page_size: z
12 | .number()
13 | .max(100)
14 | .describe("Number of results per page (max 100, default 10)"),
15 | }),
16 | outputSchema: z.object({
17 | results: z.array(z.custom()),
18 | has_more: z.boolean(),
19 | next_cursor: z.string().optional(),
20 | }),
21 | });
22 |
--------------------------------------------------------------------------------
/src/trpc/query-client.ts:
--------------------------------------------------------------------------------
1 | import {
2 | defaultShouldDehydrateQuery,
3 | QueryClient,
4 | } from "@tanstack/react-query";
5 | import SuperJSON from "superjson";
6 |
7 | export const createQueryClient = () =>
8 | new QueryClient({
9 | defaultOptions: {
10 | queries: {
11 | // With SSR, we usually want to set some default staleTime
12 | // above 0 to avoid refetching immediately on the client
13 | staleTime: 30 * 1000,
14 | },
15 | dehydrate: {
16 | serializeData: SuperJSON.serialize,
17 | shouldDehydrateQuery: (query) =>
18 | defaultShouldDehydrateQuery(query) ||
19 | query.state.status === "pending",
20 | },
21 | hydrate: {
22 | deserializeData: SuperJSON.deserialize,
23 | },
24 | },
25 | });
26 |
--------------------------------------------------------------------------------
/src/app/(general)/_hooks/use-messages.tsx:
--------------------------------------------------------------------------------
1 | import { useState, useEffect } from "react";
2 |
3 | import type { UseChatHelpers } from "@ai-sdk/react";
4 |
5 | export function useMessages({
6 | chatId,
7 | status,
8 | scrollToBottom,
9 | }: {
10 | chatId: string;
11 | status: UseChatHelpers["status"];
12 | scrollToBottom: (behavior: ScrollBehavior) => void;
13 | }) {
14 | const [hasSentMessage, setHasSentMessage] = useState(false);
15 |
16 | useEffect(() => {
17 | if (chatId) {
18 | scrollToBottom("instant");
19 | setHasSentMessage(false);
20 | }
21 | }, [chatId, scrollToBottom]);
22 |
23 | useEffect(() => {
24 | if (status === "submitted") {
25 | setHasSentMessage(true);
26 | }
27 | }, [status]);
28 |
29 | return {
30 | hasSentMessage,
31 | };
32 | }
33 |
--------------------------------------------------------------------------------
/src/hooks/use-mobile.ts:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 |
3 | const MOBILE_BREAKPOINT = 768;
4 |
5 | export function useIsMobile() {
6 | const [isMobile, setIsMobile] = React.useState(false);
7 |
8 | React.useEffect(() => {
9 | // Set initial value
10 | setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
11 |
12 | // Create media query
13 | const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
14 |
15 | // Define change handler
16 | const onChange = (e: MediaQueryListEvent) => {
17 | setIsMobile(e.matches);
18 | };
19 |
20 | // Add event listener
21 | mql.addEventListener("change", onChange);
22 |
23 | // Cleanup
24 | return () => mql.removeEventListener("change", onChange);
25 | }, []);
26 |
27 | return isMobile;
28 | }
29 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/notion/components/tool-call-display.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { HStack, VStack } from "@/components/ui/stack";
3 |
4 | interface ToolCallDisplayProps {
5 | icon: React.ComponentType<{ className?: string }>;
6 | label: string;
7 | value: string;
8 | }
9 |
10 | export const ToolCallDisplay: React.FC = ({
11 | icon: Icon,
12 | label,
13 | value,
14 | }) => {
15 | return (
16 |
17 |
18 |
19 |
20 | {label}
21 |
22 | {value}
23 |
24 |
25 | );
26 | };
27 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/exa/components/tool-call-display.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { HStack, VStack } from "@/components/ui/stack";
3 |
4 | interface ToolCallDisplayProps {
5 | icon: React.ComponentType<{ className?: string }>;
6 | label: string;
7 | value: string;
8 | }
9 |
10 | export const ToolCallDisplay: React.FC = ({
11 | icon: Icon,
12 | label,
13 | value,
14 | }) => {
15 | return (
16 |
17 |
18 |
19 |
20 | {label}
21 |
22 | "{value}"
23 |
24 |
25 | );
26 | };
27 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/exa/tools/research_paper_search/base.ts:
--------------------------------------------------------------------------------
1 | import { z } from "zod";
2 | import { createBaseTool } from "@/toolkits/create-tool";
3 |
4 | export const baseResearchPaperSearchTool = createBaseTool({
5 | description: "Search for research papers and academic content",
6 | inputSchema: z.object({
7 | query: z.string().min(1).max(100),
8 | }),
9 | outputSchema: z.object({
10 | results: z.array(
11 | z.object({
12 | title: z.string().nullable(),
13 | url: z.string().url(),
14 | content: z.string(),
15 | publishedDate: z.string().optional(),
16 | image: z.string().optional(),
17 | favicon: z.string().optional(),
18 | score: z.number().optional(),
19 | author: z.string().optional(),
20 | }),
21 | ),
22 | }),
23 | });
24 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/exa/tools/company_research/base.ts:
--------------------------------------------------------------------------------
1 | import { z } from "zod";
2 | import { createBaseTool } from "@/toolkits/create-tool";
3 |
4 | export const baseCompanyResearchTool = createBaseTool({
5 | description: "Research companies and gather detailed business information",
6 | inputSchema: z.object({
7 | company: z.string().min(1).max(100),
8 | }),
9 | outputSchema: z.object({
10 | results: z.array(
11 | z.object({
12 | title: z.string().nullable(),
13 | url: z.string().url(),
14 | content: z.string(),
15 | publishedDate: z.string().optional(),
16 | image: z.string().optional(),
17 | favicon: z.string().optional(),
18 | score: z.number().optional(),
19 | author: z.string().optional(),
20 | }),
21 | ),
22 | }),
23 | });
24 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/spotify/tools/tracks/base.ts:
--------------------------------------------------------------------------------
1 | import { z } from "zod";
2 | import { createBaseTool } from "@/toolkits/create-tool";
3 | import type { SavedTrack } from "@spotify/web-api-ts-sdk";
4 |
5 | export const getTracksBase = createBaseTool({
6 | description: "Get the user's saved tracks from Spotify.",
7 | inputSchema: z.object({
8 | limit: z
9 | .number()
10 | .min(1)
11 | .max(50)
12 | .optional()
13 | .describe(
14 | "The maximum number of items to return. Default: 20. Min: 1. Max: 50.",
15 | ),
16 | offset: z
17 | .number()
18 | .min(0)
19 | .optional()
20 | .describe("The index of the first track to return. Default: 0."),
21 | }),
22 | outputSchema: z.object({
23 | tracks: z.array(z.custom()),
24 | }),
25 | });
26 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/video/base.ts:
--------------------------------------------------------------------------------
1 | import { z } from "zod";
2 |
3 | import { allVideoModels } from "@/ai/video";
4 |
5 | import { VideoTools, baseGenerateTool } from "./tools";
6 |
7 | import type { ToolkitConfig } from "@/toolkits/types";
8 | import type { VideoModelProvider } from "@/ai/video/types";
9 |
10 | export const videoParameters = z.object({
11 | model: z.enum(
12 | allVideoModels.map((model) => `${model.provider}:${model.modelId}`) as [
13 | `${VideoModelProvider}:${string}`,
14 | ...`${VideoModelProvider}:${string}`[],
15 | ],
16 | ),
17 | });
18 |
19 | export const baseVideoToolkitConfig: ToolkitConfig<
20 | VideoTools,
21 | typeof videoParameters.shape
22 | > = {
23 | tools: {
24 | [VideoTools.Generate]: baseGenerateTool,
25 | },
26 | parameters: videoParameters,
27 | };
28 |
--------------------------------------------------------------------------------
/src/app/(general)/_components/chat/messages/utils/llm-code-block.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { parsePartialMarkdownCodeBlock } from "@llm-ui/code";
4 |
5 | import type { LLMOutputComponent } from "@llm-ui/react";
6 | import type { BundledLanguage } from "@/components/ui/code/shiki.bundle";
7 | import { CodeBlock } from "@/components/ui/code-block";
8 |
9 | export const LLMCodeBlock: LLMOutputComponent = ({ blockMatch }) => {
10 | const { code, language } = parsePartialMarkdownCodeBlock(blockMatch.output);
11 |
12 | if (!code || !language) {
13 | return null;
14 | }
15 |
16 | // @llm-ui/code bug: failing to remove trailing backticks
17 | const cleanedCode = code.replace(/```\s*$/, "").trim();
18 |
19 | return (
20 |
21 | );
22 | };
23 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/strava/tools/routes/server.ts:
--------------------------------------------------------------------------------
1 | import type { Strava } from "strava";
2 |
3 | import type { ServerToolConfig } from "@/toolkits/types";
4 |
5 | import type { getRoutesBase } from "./base";
6 |
7 | export const getRoutesToolConfigServer = (
8 | strava: Strava,
9 | ): ServerToolConfig<
10 | typeof getRoutesBase.inputSchema.shape,
11 | typeof getRoutesBase.outputSchema.shape
12 | > => {
13 | return {
14 | callback: async ({ page = 1, per_page = 30 }) => {
15 | const { id } = await strava.athletes.getLoggedInAthlete();
16 |
17 | const routes = await strava.routes.getRoutesByAthleteId({
18 | id,
19 | page,
20 | per_page,
21 | });
22 |
23 | return { routes };
24 | },
25 | message: "Successfully retrieved athlete routes from Strava.",
26 | };
27 | };
28 |
--------------------------------------------------------------------------------
/src/components/ui/textarea.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 |
3 | import { cn } from "@/lib/utils";
4 |
5 | function Textarea({ className, ...props }: React.ComponentProps<"textarea">) {
6 | return (
7 |
15 | );
16 | }
17 |
18 | export { Textarea };
19 |
--------------------------------------------------------------------------------
/src/app/(general)/_components/landing-page/contributors/user-avatar-circles.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | import { AvatarCircles } from "@/components/magicui/avatar-circles";
4 |
5 | interface UserAvatarCirclesByLoginProps {
6 | logins: string[];
7 | totalUsers: number;
8 | numAvatarsToShow?: number;
9 | size?: number;
10 | }
11 | export const UserAvatarCirclesByLogin: React.FC<
12 | UserAvatarCirclesByLoginProps
13 | > = ({ logins, totalUsers, numAvatarsToShow = 4, size = 36 }) => {
14 | const numAvatars = Math.min(totalUsers, numAvatarsToShow);
15 |
16 | return (
17 | `https://github.com/${login}.png`)}
21 | numPeople={Math.max(totalUsers - numAvatars, 0)}
22 | size={size}
23 | />
24 | );
25 | };
26 |
--------------------------------------------------------------------------------
/src/components/ui/separator.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import * as React from "react";
4 | import * as SeparatorPrimitive from "@radix-ui/react-separator";
5 |
6 | import { cn } from "@/lib/utils";
7 |
8 | function Separator({
9 | className,
10 | orientation = "horizontal",
11 | decorative = true,
12 | ...props
13 | }: React.ComponentProps) {
14 | return (
15 |
25 | );
26 | }
27 |
28 | export { Separator };
29 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/spotify/tools/playlists/base.ts:
--------------------------------------------------------------------------------
1 | import { z } from "zod";
2 | import { createBaseTool } from "@/toolkits/create-tool";
3 | import type { SimplifiedPlaylist } from "@spotify/web-api-ts-sdk";
4 |
5 | export const getPlaylistsBase = createBaseTool({
6 | description: "Get the user's Spotify playlists.",
7 | inputSchema: z.object({
8 | limit: z
9 | .number()
10 | .min(1)
11 | .max(50)
12 | .optional()
13 | .describe(
14 | "The maximum number of items to return. Default: 20. Min: 1. Max: 50.",
15 | ),
16 | offset: z
17 | .number()
18 | .min(0)
19 | .optional()
20 | .describe("The index of the first playlist to return. Default: 0."),
21 | }),
22 | outputSchema: z.object({
23 | playlists: z.array(z.custom()),
24 | }),
25 | });
26 |
--------------------------------------------------------------------------------
/prisma/migrations/20250612033842_files/migration.sql:
--------------------------------------------------------------------------------
1 | /*
2 | Warnings:
3 |
4 | - The `attachments` column on the `Message` table would be dropped and recreated. This will lead to data loss if there is data in the column.
5 |
6 | */
7 | -- AlterTable
8 | ALTER TABLE "Message" DROP COLUMN "attachments",
9 | ADD COLUMN "attachments" JSONB[];
10 |
11 | -- CreateTable
12 | CREATE TABLE "File" (
13 | "id" TEXT NOT NULL,
14 | "userId" TEXT NOT NULL,
15 | "name" TEXT NOT NULL,
16 | "contentType" TEXT NOT NULL,
17 | "url" TEXT NOT NULL,
18 | "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
19 |
20 | CONSTRAINT "File_pkey" PRIMARY KEY ("id")
21 | );
22 |
23 | -- AddForeignKey
24 | ALTER TABLE "File" ADD CONSTRAINT "File_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
25 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/google-calendar/tools/list-calendars/base.ts:
--------------------------------------------------------------------------------
1 | import { z } from "zod";
2 | import { createBaseTool } from "@/toolkits/create-tool";
3 | import type { calendar_v3 } from "googleapis";
4 |
5 | export const listCalendarsTool = createBaseTool({
6 | description: "List all calendars for the authenticated user",
7 | inputSchema: z.object({
8 | maxResults: z
9 | .number()
10 | .describe("Maximum number of calendars to return (default: 100)"),
11 | pageToken: z
12 | .string()
13 | .describe("Token for pagination (use empty string for first page)"),
14 | }),
15 | outputSchema: z.object({
16 | calendars: z.array(z.custom()),
17 | nextPageToken: z
18 | .string()
19 | .optional()
20 | .describe("Token for next page of results"),
21 | }),
22 | });
23 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/image/base.ts:
--------------------------------------------------------------------------------
1 | import type { ToolkitConfig } from "@/toolkits/types";
2 | import { ImageTools } from "./tools/tools";
3 | import { baseGenerateTool } from "./tools/generate/base";
4 | import { z } from "zod";
5 | import { allImageModels } from "@/ai/image";
6 | import type { ImageModelProvider } from "@/ai/image/types";
7 |
8 | export const imageParameters = z.object({
9 | model: z.enum(
10 | allImageModels.map((model) => `${model.provider}:${model.modelId}`) as [
11 | `${ImageModelProvider}:${string}`,
12 | ...`${ImageModelProvider}:${string}`[],
13 | ],
14 | ),
15 | });
16 |
17 | export const baseImageToolkitConfig: ToolkitConfig<
18 | ImageTools,
19 | typeof imageParameters.shape
20 | > = {
21 | tools: {
22 | [ImageTools.Generate]: baseGenerateTool,
23 | },
24 | parameters: imageParameters,
25 | };
26 |
--------------------------------------------------------------------------------
/src/app/(general)/_components/landing-page/hero/graphic/toolkit-node.tsx:
--------------------------------------------------------------------------------
1 | import React, { memo } from "react";
2 |
3 | import { Card } from "@/components/ui/card";
4 | import { AnimatedLogo } from "@/components/ui/logo";
5 |
6 | import { Handle } from "../../lib/handle";
7 |
8 | interface Props {
9 | targetRef: React.RefObject;
10 | sourceRef: React.RefObject;
11 | }
12 |
13 | export const ToolkitNode: React.FC = memo(({ targetRef, sourceRef }) => {
14 | return (
15 |
16 |
17 |
18 |
19 |
20 | );
21 | });
22 |
23 | ToolkitNode.displayName = "ToolkitNode";
24 |
--------------------------------------------------------------------------------
/src/components/ui/label.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import * as React from "react";
4 | import * as LabelPrimitive from "@radix-ui/react-label";
5 | import { cva, type VariantProps } from "class-variance-authority";
6 |
7 | import { cn } from "@/lib/utils";
8 |
9 | const labelVariants = cva(
10 | "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
11 | );
12 |
13 | const Label = React.forwardRef<
14 | React.ElementRef,
15 | React.ComponentPropsWithoutRef &
16 | VariantProps
17 | >(({ className, ...props }, ref) => (
18 |
23 | ));
24 | Label.displayName = LabelPrimitive.Root.displayName;
25 |
26 | export { Label };
27 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/video/client.tsx:
--------------------------------------------------------------------------------
1 | import { Video } from "lucide-react";
2 |
3 | import { createClientToolkit } from "@/toolkits/create-toolkit";
4 |
5 | import { ToolkitGroups } from "@/toolkits/types";
6 |
7 | import { baseVideoToolkitConfig } from "./base";
8 |
9 | import { VideoTools } from "./tools";
10 |
11 | import { generateToolConfigClient } from "./tools/generate/client";
12 |
13 | import { videoEnvVars } from "./env-vars";
14 | import { VideoForm } from "./form";
15 |
16 | export const videoClientToolkit = createClientToolkit(
17 | baseVideoToolkitConfig,
18 | {
19 | name: "Video",
20 | description: "Generate videos with AI",
21 | icon: Video,
22 | form: VideoForm,
23 | type: ToolkitGroups.Native,
24 | envVars: videoEnvVars,
25 | },
26 | {
27 | [VideoTools.Generate]: generateToolConfigClient,
28 | },
29 | );
30 |
--------------------------------------------------------------------------------
/.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.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 | pnpm-workspace.yaml
34 |
35 | # local env files
36 | # 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
37 | .env
38 | .env.*
39 | !.env.example
40 |
41 | # vercel
42 | .vercel
43 |
44 | # typescript
45 | *.tsbuildinfo
46 |
47 | # idea files
48 | .idea
--------------------------------------------------------------------------------
/src/app/api/auth/guest/route.ts:
--------------------------------------------------------------------------------
1 | import { signIn } from "@/server/auth";
2 | import { IS_DEVELOPMENT } from "@/lib/constants";
3 | import { getToken } from "next-auth/jwt";
4 | import { type NextRequest, NextResponse } from "next/server";
5 |
6 | export async function GET(request: NextRequest) {
7 | if (!IS_DEVELOPMENT) {
8 | return NextResponse.json({ error: "Not allowed" }, { status: 403 });
9 | }
10 |
11 | const searchParams = request.nextUrl.searchParams;
12 | const redirectUrl = searchParams.get("redirectUrl") ?? "/";
13 |
14 | const token = await getToken({
15 | req: request,
16 | secret: process.env.AUTH_SECRET,
17 | secureCookie: false,
18 | });
19 |
20 | if (token) {
21 | return NextResponse.redirect(new URL("/", request.url));
22 | }
23 |
24 | return signIn("guest", { redirect: true, redirectTo: redirectUrl });
25 | }
26 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/strava/tools/activities/server.ts:
--------------------------------------------------------------------------------
1 | import type { Strava } from "strava";
2 |
3 | import type { ServerToolConfig } from "@/toolkits/types";
4 |
5 | import type { getActivitiesBase } from "./base";
6 |
7 | export const getActivitiesToolConfigServer = (
8 | strava: Strava,
9 | ): ServerToolConfig<
10 | typeof getActivitiesBase.inputSchema.shape,
11 | typeof getActivitiesBase.outputSchema.shape
12 | > => {
13 | return {
14 | callback: async ({ page = 1, per_page = 30, before, after }) => {
15 | const activities = await strava.activities.getLoggedInAthleteActivities({
16 | page,
17 | per_page,
18 | before,
19 | after,
20 | });
21 |
22 | return {
23 | activities,
24 | };
25 | },
26 | message: "Successfully retrieved athlete activities from Strava.",
27 | };
28 | };
29 |
--------------------------------------------------------------------------------
/prisma/migrations/20250616064236_workbenches/migration.sql:
--------------------------------------------------------------------------------
1 | -- AlterTable
2 | ALTER TABLE "Chat" ADD COLUMN "workbenchId" TEXT;
3 |
4 | -- CreateTable
5 | CREATE TABLE "Workbench" (
6 | "id" TEXT NOT NULL,
7 | "name" TEXT NOT NULL,
8 | "systemPrompt" TEXT NOT NULL,
9 | "toolkitIds" TEXT[],
10 | "userId" TEXT NOT NULL,
11 | "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
12 | "updatedAt" TIMESTAMP(3) NOT NULL,
13 |
14 | CONSTRAINT "Workbench_pkey" PRIMARY KEY ("id")
15 | );
16 |
17 | -- AddForeignKey
18 | ALTER TABLE "Chat" ADD CONSTRAINT "Chat_workbenchId_fkey" FOREIGN KEY ("workbenchId") REFERENCES "Workbench"("id") ON DELETE SET NULL ON UPDATE CASCADE;
19 |
20 | -- AddForeignKey
21 | ALTER TABLE "Workbench" ADD CONSTRAINT "Workbench_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
22 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/google-calendar/tools/list-calendars/server.ts:
--------------------------------------------------------------------------------
1 | import { type listCalendarsTool } from "./base";
2 | import type { ServerToolConfig } from "@/toolkits/types";
3 | import type { calendar_v3 } from "googleapis";
4 |
5 | export const googleCalendarListCalendarsToolConfigServer = (
6 | calendar: calendar_v3.Calendar,
7 | ): ServerToolConfig<
8 | typeof listCalendarsTool.inputSchema.shape,
9 | typeof listCalendarsTool.outputSchema.shape
10 | > => {
11 | return {
12 | callback: async ({ maxResults, pageToken }) => {
13 | const response = await calendar.calendarList.list({
14 | maxResults: maxResults,
15 | pageToken: pageToken,
16 | });
17 |
18 | return {
19 | calendars: response.data.items ?? [],
20 | nextPageToken: response.data.nextPageToken ?? undefined,
21 | };
22 | },
23 | };
24 | };
25 |
--------------------------------------------------------------------------------
/src/app/(general)/[id]/page.tsx:
--------------------------------------------------------------------------------
1 | import { notFound, redirect } from "next/navigation";
2 |
3 | import { Chat } from "@/app/(general)/_components/chat";
4 | import { api } from "@/trpc/server";
5 |
6 | import { auth } from "@/server/auth";
7 |
8 | export default async function Page(props: { params: Promise<{ id: string }> }) {
9 | const params = await props.params;
10 | const { id } = params;
11 |
12 | const session = await auth();
13 |
14 | if (!session) {
15 | redirect(`/login?redirect=/${id}`);
16 | }
17 |
18 | const chat = await api.chats.getChat(id);
19 |
20 | if (!chat) {
21 | notFound();
22 | }
23 |
24 | return (
25 | <>
26 |
32 | >
33 | );
34 | }
35 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/mem0/tools/search_memories/base.ts:
--------------------------------------------------------------------------------
1 | import { z } from "zod";
2 | import { createBaseTool } from "@/toolkits/create-tool";
3 |
4 | export const baseSearchMemoriesTool = createBaseTool({
5 | description:
6 | "Search through stored memories. This method is called ANYTIME the user asks anything.",
7 | inputSchema: z.object({
8 | query: z
9 | .string()
10 | .describe(
11 | "The search query. This is the query that the user has asked for. Example: 'What did I tell you about the weather last week?' or 'What did I tell you about my friend John?'",
12 | ),
13 | }),
14 | outputSchema: z.object({
15 | memories: z.array(
16 | z.object({
17 | memory: z.string(),
18 | score: z.number(),
19 | metadata: z.record(z.any()).optional(),
20 | }),
21 | ),
22 | query: z.string(),
23 | }),
24 | });
25 |
--------------------------------------------------------------------------------
/src/lib/constants.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Global validation constants for the application
3 | */
4 |
5 | export const VALIDATION_LIMITS = {
6 | /** Maximum length for message content and text parts */
7 | MESSAGE_MAX_LENGTH: 16348,
8 |
9 | /** Maximum length for file and attachment names */
10 | FILE_NAME_MAX_LENGTH: 2000,
11 |
12 | /** Maximum file size for uploads (in bytes) */
13 | FILE_MAX_SIZE: 5 * 1024 * 1024, // 5MB
14 | } as const;
15 |
16 | /**
17 | * Convenience exports for commonly used limits
18 | */
19 | export const MESSAGE_MAX_LENGTH = VALIDATION_LIMITS.MESSAGE_MAX_LENGTH;
20 | export const FILE_NAME_MAX_LENGTH = VALIDATION_LIMITS.FILE_NAME_MAX_LENGTH;
21 | export const FILE_MAX_SIZE = VALIDATION_LIMITS.FILE_MAX_SIZE;
22 |
23 | export const IS_DEVELOPMENT = process.env.NODE_ENV === "development";
24 | export const IS_PRODUCTION = process.env.NODE_ENV === "production";
25 |
--------------------------------------------------------------------------------
/src/app/(general)/_components/landing-page/workbench-examples/index.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | import { Section } from "../lib/section";
4 | import { MiniHeading } from "../lib/heading";
5 |
6 | import { WorkbenchCard } from "./card";
7 |
8 | import { SECTIONS } from "../sections";
9 |
10 | import { workbenchExamples } from "./data";
11 |
12 | export const WorkbenchExamplesSection: React.FC = () => {
13 | return (
14 |
15 |
16 |
17 |
18 | {workbenchExamples.map((workbench) => (
19 |
20 | ))}
21 |
22 |
23 |
24 | );
25 | };
26 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: Build, Lint, and Type Check
2 |
3 | on:
4 | pull_request:
5 | branches: ["**"]
6 |
7 | jobs:
8 | ci:
9 | runs-on: ubuntu-latest
10 |
11 | steps:
12 | - name: Checkout code
13 | uses: actions/checkout@v4
14 |
15 | - name: Setup pnpm
16 | uses: pnpm/action-setup@v4
17 | with:
18 | version: 10.3.0
19 |
20 | - name: Setup Node.js
21 | uses: actions/setup-node@v4
22 | with:
23 | node-version: "18"
24 | cache: "pnpm"
25 |
26 | - name: Install dependencies
27 | run: pnpm install
28 |
29 | - name: Check formatting
30 | run: pnpm run format:check
31 |
32 | - name: Run linting and type check
33 | run: SKIP_ENV_VALIDATION=1 pnpm run check
34 |
35 | - name: Build project
36 | run: SKIP_ENV_VALIDATION=1 pnpm run build-pure
37 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/strava/tools/index.ts:
--------------------------------------------------------------------------------
1 | export enum StravaTools {
2 | GetAthleteProfile = "get-athlete-profile",
3 | GetAthleteActivities = "get-athlete-activities",
4 | GetActivityDetails = "get-activity-details",
5 | GetAthleteStats = "get-athlete-stats",
6 | ExploreSegments = "explore-segments",
7 | GetSegmentDetails = "get-segment-details",
8 | GetRoutes = "get-routes",
9 | GetAthleteZones = "get-athlete-zones",
10 | }
11 |
12 | export { getAthleteBase } from "./profile/base";
13 | export { getActivitiesBase } from "./activities/base";
14 | export { getActivityDetailsBase } from "./activity-details/base";
15 | export { getAthleteStatsBase } from "./stats/base";
16 | export { exploreSegmentsBase } from "./explore-segments/base";
17 | export { getSegmentDetailsBase } from "./segment/base";
18 | export { getRoutesBase } from "./routes/base";
19 | export { getAthleteZonesBase } from "./zones/base";
20 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/video/env-vars.tsx:
--------------------------------------------------------------------------------
1 | import { Link } from "../components/link";
2 |
3 | import type { EnvVar, EnvVars } from "@/toolkits/types";
4 | import type { VideoModelProvider } from "@/ai/video/types";
5 |
6 | const lumaEnvVar = {
7 | key: "LUMA_API_KEY",
8 | description: (
9 |
10 | Get an Luma API Key here
11 |
12 | ),
13 | };
14 |
15 | export const videoEnvVars: EnvVars = [
16 | {
17 | type: "any",
18 | keys: [lumaEnvVar],
19 | },
20 | {
21 | type: "all",
22 | keys: ["BLOB_READ_WRITE_TOKEN"],
23 | description: (
24 |
25 | Get a Vercel Blob Token{" "}
26 | here
27 |
28 | ),
29 | },
30 | ];
31 |
32 | export const videoEnvVarMap: Record = {
33 | luma: lumaEnvVar,
34 | };
35 |
--------------------------------------------------------------------------------
/src/app/(general)/workbench/[id]/page.tsx:
--------------------------------------------------------------------------------
1 | import { notFound } from "next/navigation";
2 |
3 | import { Chat } from "@/app/(general)/_components/chat";
4 | import { api } from "@/trpc/server";
5 | import { generateUUID } from "@/lib/utils";
6 |
7 | export default async function WorkbenchPage(props: {
8 | params: Promise<{ id: string }>;
9 | }) {
10 | const params = await props.params;
11 | const { id } = params;
12 |
13 | try {
14 | const workbench = await api.workbenches.getWorkbench(id);
15 |
16 | if (!workbench) {
17 | notFound();
18 | }
19 |
20 | const chatId = generateUUID();
21 |
22 | return (
23 |
30 | );
31 | } catch (error) {
32 | console.error(error);
33 | notFound();
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/image/client.tsx:
--------------------------------------------------------------------------------
1 | import { ImageIcon } from "lucide-react";
2 |
3 | import { ImageTools } from "./tools/tools";
4 | import { createClientToolkit } from "@/toolkits/create-toolkit";
5 | import { generateToolConfigClient } from "./tools/generate/client";
6 | import { baseImageToolkitConfig } from "./base";
7 | import { ToolkitGroups } from "@/toolkits/types";
8 | import { Form } from "./form";
9 | import { imageEnvVars } from "./env-vars";
10 |
11 | export const imageClientToolkit = createClientToolkit<
12 | ImageTools,
13 | typeof baseImageToolkitConfig.parameters.shape
14 | >(
15 | baseImageToolkitConfig,
16 | {
17 | name: "Image Generation",
18 | description: "Let your creativity flow",
19 | icon: ImageIcon,
20 | form: Form,
21 | type: ToolkitGroups.Native,
22 | envVars: imageEnvVars,
23 | },
24 | {
25 | [ImageTools.Generate]: generateToolConfigClient,
26 | },
27 | );
28 |
--------------------------------------------------------------------------------
/src/app/(general)/_components/chat/messages/greeting.tsx:
--------------------------------------------------------------------------------
1 | import { motion } from "motion/react";
2 |
3 | export const Greeting = () => {
4 | return (
5 |
9 |
16 | Hello there!
17 |
18 |
25 | How can I help you today?
26 |
27 |
28 | );
29 | };
30 |
--------------------------------------------------------------------------------
/src/app/(general)/_components/landing-page/banner/index.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | import { HStack } from "@/components/ui/stack";
4 | import { ScrollToSection } from "../lib/scroll-to-section";
5 | import { SECTIONS } from "../sections";
6 |
7 | export const Banner: React.FC = () => {
8 | return (
9 |
10 |
11 |
12 | $6,000 available for contributors
13 |
14 |
15 |
16 | Learn More
17 |
18 |
19 |
20 |
21 | );
22 | };
23 |
--------------------------------------------------------------------------------
/src/app/(general)/workbench/[id]/[chatId]/page.tsx:
--------------------------------------------------------------------------------
1 | import { notFound } from "next/navigation";
2 |
3 | import { auth } from "@/server/auth";
4 | import { Chat } from "@/app/(general)/_components/chat";
5 | import { api } from "@/trpc/server";
6 |
7 | export default async function Page(props: {
8 | params: Promise<{ id: string; chatId: string }>;
9 | }) {
10 | const params = await props.params;
11 | const { id, chatId } = params;
12 |
13 | const session = await auth();
14 |
15 | const [chat, workbench] = await Promise.all([
16 | api.chats.getChat(chatId),
17 | api.workbenches.getWorkbench(id),
18 | ]);
19 |
20 | if (!chat || !workbench) {
21 | notFound();
22 | }
23 |
24 | return (
25 |
32 | );
33 | }
34 |
--------------------------------------------------------------------------------
/src/ai/language/models/qwen.ts:
--------------------------------------------------------------------------------
1 | import type { LanguageModel } from "@/ai/language/types";
2 |
3 | const qwenModelData: Omit[] = [
4 | {
5 | name: "Qwen QwQ 32B",
6 | modelId: "qwq-32b",
7 | description:
8 | "Qwen QWQ 32B is a large language model optimized for various natural language processing tasks",
9 | capabilities: [],
10 | bestFor: ["General purpose", "Text generation", "Conversation"],
11 | contextLength: 131072,
12 | },
13 | {
14 | name: "Qwen 3 32B",
15 | modelId: "qwen3-32b",
16 | description:
17 | "Qwen 3 32B is the latest generation of Qwen models with enhanced capabilities",
18 | capabilities: [],
19 | bestFor: ["Advanced reasoning", "Code generation", "Creative writing"],
20 | contextLength: 131072,
21 | },
22 | ];
23 |
24 | export const qwenModels: LanguageModel[] = qwenModelData.map((model) => ({
25 | ...model,
26 | provider: "qwen",
27 | }));
28 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/github/components/user-avatar.tsx:
--------------------------------------------------------------------------------
1 | import { memo } from "react";
2 |
3 | import { SiGithub } from "@icons-pack/react-simple-icons";
4 |
5 | import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
6 |
7 | import { cn } from "@/lib/utils";
8 |
9 | interface Props {
10 | login: string;
11 | className?: string;
12 | style?: React.CSSProperties;
13 | }
14 |
15 | export const GithubAvatar = memo(function GithubAvatar({
16 | login,
17 | className,
18 | style,
19 | }: Props) {
20 | return (
21 |
22 |
27 |
28 |
29 |
30 |
31 | );
32 | });
33 |
--------------------------------------------------------------------------------
/src/app/(general)/workbench/[id]/layout.tsx:
--------------------------------------------------------------------------------
1 | import { api } from "@/trpc/server";
2 | import { WorkbenchHeader } from "./_components/header";
3 | import { notFound, redirect } from "next/navigation";
4 | import { auth } from "@/server/auth";
5 |
6 | export default async function WorkbenchLayout({
7 | children,
8 | params,
9 | }: {
10 | children: React.ReactNode;
11 | params: Promise<{ id: string }>;
12 | }) {
13 | const { id } = await params;
14 |
15 | const session = await auth();
16 |
17 | if (!session) {
18 | redirect(`/login?redirect=/workbench/${id}`);
19 | }
20 |
21 | const workbench = await api.workbenches.getWorkbench(id);
22 |
23 | if (!workbench) {
24 | notFound();
25 | }
26 |
27 | return (
28 |
29 |
30 |
{children}
31 |
32 | );
33 | }
34 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/google-drive/tools/read-file/base.ts:
--------------------------------------------------------------------------------
1 | import { z } from "zod";
2 | import { createBaseTool } from "@/toolkits/create-tool";
3 |
4 | export const readFileTool = createBaseTool({
5 | description: "Read the contents of a file from Google Drive",
6 | inputSchema: z.object({
7 | fileId: z.string().describe("ID of the file to read"),
8 | exportFormat: z
9 | .string()
10 | .describe(
11 | "Export format for Google Workspace files (e.g., 'text/plain', 'text/csv', 'text/markdown') (leave blank for auto-detection)",
12 | ),
13 | }),
14 | outputSchema: z.object({
15 | content: z.string().describe("File content as text"),
16 | mimeType: z.string().describe("MIME type of the content"),
17 | fileName: z.string().describe("Name of the file"),
18 | size: z.number().optional().describe("Size of the content in bytes"),
19 | encoding: z.string().optional().describe("Content encoding used"),
20 | }),
21 | });
22 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/twitter/tools/tweets/base.ts:
--------------------------------------------------------------------------------
1 | import { z } from "zod";
2 | import { createBaseTool } from "@/toolkits/create-tool";
3 | import type { TweetUserTimelineV2Paginator } from "twitter-api-v2";
4 |
5 | export const getLatestTweetsTool = createBaseTool({
6 | description: "Get the latest tweets from a Twitter user (up to 100 tweets)",
7 | inputSchema: z.object({
8 | username: z
9 | .string()
10 | .describe(
11 | "Twitter username (without @ symbol). Example: 'elonmusk', 'twitter'",
12 | ),
13 | max_results: z
14 | .number()
15 | .min(1)
16 | .max(100)
17 | .describe("Number of tweets to retrieve (max 100, default 10)"),
18 | exclude_retweets: z.boolean().describe("Exclude retweets from results"),
19 | exclude_replies: z.boolean().describe("Exclude replies from results"),
20 | }),
21 | outputSchema: z.object({
22 | tweets: z.custom(),
23 | }),
24 | });
25 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/exa/tools/search/client.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Search } from "lucide-react";
3 |
4 | import type { baseSearchTool } from "./base";
5 | import type { ClientToolConfig } from "@/toolkits/types";
6 | import { ToolCallDisplay, ResultsList } from "../../components";
7 |
8 | export const exaSearchToolConfigClient: ClientToolConfig<
9 | typeof baseSearchTool.inputSchema.shape,
10 | typeof baseSearchTool.outputSchema.shape
11 | > = {
12 | CallComponent: ({ args }) => {
13 | return (
14 |
19 | );
20 | },
21 | ResultComponent: ({ result }) => {
22 | return (
23 |
29 | );
30 | },
31 | };
32 |
--------------------------------------------------------------------------------
/src/app/(general)/account/page.tsx:
--------------------------------------------------------------------------------
1 | import { auth } from "@/server/auth";
2 |
3 | import { redirect } from "next/navigation";
4 |
5 | import { api } from "@/trpc/server";
6 |
7 | import { AccountHeader } from "./components/header";
8 | import { AccountTabs } from "./components/tabs";
9 |
10 | const AccountPage = async ({
11 | searchParams,
12 | }: {
13 | searchParams: Promise<{ tab?: string }>;
14 | }) => {
15 | const { tab } = await searchParams;
16 |
17 | const session = await auth();
18 |
19 | if (!session) {
20 | redirect("/login?redirect=/account");
21 | }
22 |
23 | const user = await api.users.getCurrentUser();
24 |
25 | if (!user) {
26 | redirect("/login?redirect=/account");
27 | }
28 |
29 | return (
30 |
34 | );
35 | };
36 |
37 | export default AccountPage;
38 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/etsy/tools/get-listings/client.tsx:
--------------------------------------------------------------------------------
1 | import { Search } from "lucide-react";
2 | import type { ClientToolConfig } from "@/toolkits/types";
3 | import type { getListings } from "./base";
4 |
5 | export const getListingsClientConfig: ClientToolConfig<
6 | typeof getListings.inputSchema.shape,
7 | typeof getListings.outputSchema.shape
8 | > = {
9 | CallComponent: ({ isPartial }) => (
10 |
11 |
12 | {isPartial && ...}
13 |
14 | ),
15 | ResultComponent: ({ result: { results } }) =>
16 | results.length > 0 ? (
17 |
18 |
Listings
19 | {results.map((listing) => (
20 |
{listing.title}
21 | ))}
22 |
23 | ) : (
24 | No listings found
25 | ),
26 | };
27 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/strava/tools/activities/base.ts:
--------------------------------------------------------------------------------
1 | import { z } from "zod";
2 |
3 | import { createBaseTool } from "@/toolkits/create-tool";
4 |
5 | import type { SummaryActivity } from "strava";
6 |
7 | export const getActivitiesBase = createBaseTool({
8 | description:
9 | "Get the authenticated athlete's activities with filtering options",
10 | inputSchema: z.object({
11 | page: z.number().optional().describe("Page number for pagination"),
12 | per_page: z
13 | .number()
14 | .optional()
15 | .describe("Number of activities per page (max 200)"),
16 | before: z
17 | .number()
18 | .optional()
19 | .describe("Seconds since Unix epoch to filter activities before"),
20 | after: z
21 | .number()
22 | .optional()
23 | .describe("Seconds since Unix epoch to filter activities after"),
24 | }),
25 | outputSchema: z.object({
26 | activities: z.array(z.custom()),
27 | }),
28 | });
29 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/exa/tools/crawling/client.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Link } from "lucide-react";
3 | import type { baseCrawlingTool } from "./base";
4 | import type { ClientToolConfig } from "@/toolkits/types";
5 | import { ToolCallDisplay, ResultsList } from "../../components";
6 |
7 | export const exaCrawlingToolConfigClient: ClientToolConfig<
8 | typeof baseCrawlingTool.inputSchema.shape,
9 | typeof baseCrawlingTool.outputSchema.shape
10 | > = {
11 | CallComponent: ({ args }) => {
12 | return (
13 |
18 | );
19 | },
20 | ResultComponent: ({ result }) => {
21 | return (
22 |
28 | );
29 | },
30 | };
31 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/strava/tools/activity-details/server.ts:
--------------------------------------------------------------------------------
1 | import type { Strava } from "strava";
2 |
3 | import type { ServerToolConfig } from "@/toolkits/types";
4 |
5 | import type { getActivityDetailsBase } from "./base";
6 |
7 | export const getActivityDetailsToolConfigServer = (
8 | strava: Strava,
9 | ): ServerToolConfig<
10 | typeof getActivityDetailsBase.inputSchema.shape,
11 | typeof getActivityDetailsBase.outputSchema.shape
12 | > => {
13 | return {
14 | callback: async ({ id, include_all_efforts = false }) => {
15 | const params = new URLSearchParams();
16 | if (include_all_efforts) {
17 | params.append("include_all_efforts", "true");
18 | }
19 |
20 | const activity = await strava.activities.getActivityById({
21 | id,
22 | include_all_efforts,
23 | });
24 |
25 | return {
26 | activity,
27 | };
28 | },
29 | message: "Successfully retrieved activity details from Strava.",
30 | };
31 | };
32 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/exa/components/results-list.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { ResultItem, type ResultData } from "./result-item";
3 |
4 | interface ResultsListProps {
5 | results: ResultData[];
6 | title: string;
7 | emptyMessage: string;
8 | linkText?: string;
9 | }
10 |
11 | export const ResultsList: React.FC = ({
12 | results,
13 | title,
14 | emptyMessage,
15 | linkText,
16 | }) => {
17 | if (!results.length) {
18 | return {emptyMessage}
;
19 | }
20 |
21 | return (
22 |
23 |
{title}
24 |
25 | {results.map((result, index) => (
26 |
32 | ))}
33 |
34 |
35 | );
36 | };
37 |
--------------------------------------------------------------------------------
/src/ai/language/models/perplexity.ts:
--------------------------------------------------------------------------------
1 | import {
2 | LanguageModelCapability,
3 | type LanguageModel,
4 | } from "@/ai/language/types";
5 |
6 | const perplexityModelData: Omit[] = [
7 | {
8 | name: "Sonar Pro",
9 | modelId: "sonar-pro",
10 | description: "Next-generation Sonar with enhanced reasoning",
11 | capabilities: [LanguageModelCapability.WebSearch],
12 | bestFor: ["Complex reasoning", "Advanced analysis", "Research"],
13 | contextLength: 2000000,
14 | },
15 | {
16 | name: "Sonar",
17 | modelId: "sonar",
18 | description: "Fast version of Sonar for quick responses",
19 | capabilities: [LanguageModelCapability.WebSearch],
20 | bestFor: ["Quick tasks", "Real-time responses", "Efficient processing"],
21 | contextLength: 1000000,
22 | },
23 | ];
24 |
25 | export const perplexityModels: LanguageModel[] = perplexityModelData.map(
26 | (model) => ({
27 | ...model,
28 | provider: "perplexity",
29 | }),
30 | );
31 |
--------------------------------------------------------------------------------
/src/ai/image/models/fal.ts:
--------------------------------------------------------------------------------
1 | import type { ImageModel } from "../types";
2 |
3 | const falImageModelsData: Omit[] = [
4 | {
5 | name: "Flux Dev",
6 | modelId: "fal-ai/flux/dev",
7 | },
8 | {
9 | name: "Flux LoRA",
10 | modelId: "fal-ai/flux-lora",
11 | },
12 | {
13 | name: "Flux Pro v1.1 Ultra",
14 | modelId: "fal-ai/flux-pro/v1.1-ultra",
15 | },
16 | {
17 | name: "Ideogram v2",
18 | modelId: "fal-ai/ideogram/v2",
19 | },
20 | {
21 | name: "Recraft v3",
22 | modelId: "fal-ai/recraft-v3",
23 | },
24 | {
25 | name: "Stable Diffusion 3.5 Large",
26 | modelId: "fal-ai/stable-diffusion-3.5-large",
27 | },
28 | {
29 | name: "Hyper SDXL",
30 | modelId: "fal-ai/hyper-sdxl",
31 | },
32 | {
33 | name: "Fast SDXL",
34 | modelId: "fal-ai/fast-sdxl",
35 | },
36 | ];
37 |
38 | export const falImageModels: ImageModel[] = falImageModelsData.map((model) => ({
39 | ...model,
40 | provider: "fal",
41 | }));
42 |
--------------------------------------------------------------------------------
/src/app/(general)/_components/landing-page/top-toolkits/index.tsx:
--------------------------------------------------------------------------------
1 | import { api } from "@/trpc/server";
2 |
3 | import { Section } from "../lib/section";
4 | import { MiniHeading } from "../lib/heading";
5 |
6 | import { ToolkitCard } from "./toolkit-card";
7 |
8 | import { SECTIONS } from "../sections";
9 |
10 | import type { Toolkits as ToolkitNames } from "@/toolkits/toolkits/shared";
11 |
12 | export const TopToolkitsSection = async () => {
13 | const topToolkits = await api.tools.getTopToolkits();
14 |
15 | return (
16 |
28 | );
29 | };
30 |
--------------------------------------------------------------------------------
/src/app/_components/navbar/color-mode-toggle.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { useTheme } from "next-themes";
4 |
5 | import { Button } from "@/components/ui/button";
6 | import { Moon, Sun } from "lucide-react";
7 |
8 | export const ColorModeToggle = () => {
9 | const { theme, setTheme } = useTheme();
10 |
11 | return (
12 | <>
13 |
25 | >
26 | );
27 | };
28 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/google-calendar/lib/index.ts:
--------------------------------------------------------------------------------
1 | // Calendar client utilities
2 | export { createCalendarClient } from "./calendar-client";
3 |
4 | // Event fetching utilities
5 | export {
6 | fetchEvents,
7 | fetchEventsFromMultipleCalendars,
8 | filterTimedEvents,
9 | } from "./event-fetcher";
10 |
11 | // Timezone utilities
12 | export {
13 | getUserTimezone,
14 | createTimeRange,
15 | formatDateInTimezone,
16 | formatTimeInTimezone,
17 | } from "./timezone-utils";
18 |
19 | // Date utilities
20 | export {
21 | getTodayDate,
22 | addDaysToDate,
23 | applyDateDefaults,
24 | doRangesOverlap,
25 | minutesToMs,
26 | msToMinutes,
27 | } from "./date-utils";
28 |
29 | // Types
30 | export type {
31 | CalendarEvent,
32 | Calendar,
33 | EventAttendee,
34 | EventDateTime,
35 | EventReminder,
36 | TimeSlot,
37 | ConflictingEvent,
38 | SearchPeriod,
39 | AvailabilityResult,
40 | FindAvailabilityParams,
41 | EventFetchParams,
42 | CalendarClientConfig,
43 | } from "./types";
44 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/exa/tools/competitor_finder/client.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Users } from "lucide-react";
3 | import type { baseCompetitorFinderTool } from "./base";
4 | import type { ClientToolConfig } from "@/toolkits/types";
5 | import { ToolCallDisplay, ResultsList } from "../../components";
6 |
7 | export const exaCompetitorFinderToolConfigClient: ClientToolConfig<
8 | typeof baseCompetitorFinderTool.inputSchema.shape,
9 | typeof baseCompetitorFinderTool.outputSchema.shape
10 | > = {
11 | CallComponent: ({ args }) => {
12 | return (
13 |
18 | );
19 | },
20 | ResultComponent: ({ result }) => {
21 | return (
22 |
28 | );
29 | },
30 | };
31 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/exa/tools/linkedin_search/client.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Linkedin } from "lucide-react";
3 | import type { baseLinkedinSearchTool } from "./base";
4 | import type { ClientToolConfig } from "@/toolkits/types";
5 | import { ToolCallDisplay, ResultsList } from "../../components";
6 |
7 | export const exaLinkedinSearchToolConfigClient: ClientToolConfig<
8 | typeof baseLinkedinSearchTool.inputSchema.shape,
9 | typeof baseLinkedinSearchTool.outputSchema.shape
10 | > = {
11 | CallComponent: ({ args }) => {
12 | return (
13 |
18 | );
19 | },
20 | ResultComponent: ({ result }) => {
21 | return (
22 |
28 | );
29 | },
30 | };
31 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/exa/tools/wikipedia_search/client.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Globe } from "lucide-react";
3 | import type { baseWikipediaSearchTool } from "./base";
4 | import type { ClientToolConfig } from "@/toolkits/types";
5 | import { ToolCallDisplay, ResultsList } from "../../components";
6 |
7 | export const exaWikipediaSearchToolConfigClient: ClientToolConfig<
8 | typeof baseWikipediaSearchTool.inputSchema.shape,
9 | typeof baseWikipediaSearchTool.outputSchema.shape
10 | > = {
11 | CallComponent: ({ args }) => {
12 | return (
13 |
18 | );
19 | },
20 | ResultComponent: ({ result }) => {
21 | return (
22 |
28 | );
29 | },
30 | };
31 |
--------------------------------------------------------------------------------
/src/trpc/server.ts:
--------------------------------------------------------------------------------
1 | import "server-only";
2 |
3 | import { createHydrationHelpers } from "@trpc/react-query/rsc";
4 | import { headers } from "next/headers";
5 | import { cache } from "react";
6 |
7 | import { createCaller, type AppRouter } from "@/server/api/root";
8 | import { createTRPCContext } from "@/server/api/trpc";
9 | import { createQueryClient } from "./query-client";
10 |
11 | /**
12 | * This wraps the `createTRPCContext` helper and provides the required context for the tRPC API when
13 | * handling a tRPC call from a React Server Component.
14 | */
15 | const createContext = cache(async () => {
16 | const heads = new Headers(await headers());
17 | heads.set("x-trpc-source", "rsc");
18 |
19 | return createTRPCContext({
20 | headers: heads,
21 | });
22 | });
23 |
24 | const getQueryClient = cache(createQueryClient);
25 | const caller = createCaller(createContext);
26 |
27 | export const { trpc: api, HydrateClient } = createHydrationHelpers(
28 | caller,
29 | getQueryClient,
30 | );
31 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/exa/tools/github_search/client.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import type { baseGithubSearchTool } from "./base";
3 | import type { ClientToolConfig } from "@/toolkits/types";
4 | import { ToolCallDisplay, ResultsList } from "../../components";
5 | import { SiGithub } from "@icons-pack/react-simple-icons";
6 |
7 | export const exaGithubSearchToolConfigClient: ClientToolConfig<
8 | typeof baseGithubSearchTool.inputSchema.shape,
9 | typeof baseGithubSearchTool.outputSchema.shape
10 | > = {
11 | CallComponent: ({ args }) => {
12 | return (
13 |
18 | );
19 | },
20 | ResultComponent: ({ result }) => {
21 | return (
22 |
28 | );
29 | },
30 | };
31 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/exa/tools/company_research/client.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Building } from "lucide-react";
3 | import type { baseCompanyResearchTool } from "./base";
4 | import type { ClientToolConfig } from "@/toolkits/types";
5 | import { ToolCallDisplay, ResultsList } from "../../components";
6 |
7 | export const exaCompanyResearchToolConfigClient: ClientToolConfig<
8 | typeof baseCompanyResearchTool.inputSchema.shape,
9 | typeof baseCompanyResearchTool.outputSchema.shape
10 | > = {
11 | CallComponent: ({ args }) => {
12 | return (
13 |
18 | );
19 | },
20 | ResultComponent: ({ result }) => {
21 | return (
22 |
28 | );
29 | },
30 | };
31 |
--------------------------------------------------------------------------------
/src/app/(general)/_components/landing-page/lib/handle.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | import { cn } from "@/lib/utils";
4 |
5 | interface Props {
6 | side: "left" | "right" | "top" | "bottom";
7 | className?: string;
8 | }
9 |
10 | export const Handle = React.forwardRef(
11 | ({ side, className }, ref) => {
12 | return (
13 |
28 | );
29 | },
30 | );
31 | Handle.displayName = "Handle";
32 |
--------------------------------------------------------------------------------
/src/app/admin/toolkits/_components/sync-button.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { Button } from "@/components/ui/button";
4 | import { useRouter } from "next/navigation";
5 | import { api } from "@/trpc/react";
6 | import { toast } from "sonner";
7 | import { Check, Loader2 } from "lucide-react";
8 |
9 | export const SyncButton = () => {
10 | const router = useRouter();
11 | const utils = api.useUtils();
12 | const {
13 | mutate: syncToolUsage,
14 | isPending,
15 | isSuccess,
16 | } = api.sync.syncToolUsage.useMutation({
17 | onSuccess: async () => {
18 | await utils.toolkits.getOverallStats.invalidate();
19 | router.refresh();
20 | toast.success("Tool usage synced");
21 | },
22 | });
23 |
24 | return (
25 |
34 | );
35 | };
36 |
--------------------------------------------------------------------------------
/src/app/admin/layout.tsx:
--------------------------------------------------------------------------------
1 | import { SidebarInset, SidebarProvider } from "@/components/ui/sidebar";
2 |
3 | import { AdminSidebar } from "@/app/admin/_components/admin-sidebar";
4 | import { Navbar } from "@/app/_components/navbar";
5 | import { auth } from "@/server/auth";
6 | import { forbidden, unauthorized } from "next/navigation";
7 | import { IS_DEVELOPMENT } from "@/lib/constants";
8 |
9 | export default async function AdminLayout({
10 | children,
11 | }: Readonly<{ children: React.ReactNode }>) {
12 | const session = await auth();
13 |
14 | if (!session) {
15 | return unauthorized();
16 | }
17 |
18 | if (session.user.role !== "ADMIN" && !IS_DEVELOPMENT) {
19 | return forbidden();
20 | }
21 |
22 | return (
23 |
24 |
25 |
26 |
27 |
28 | {children}
29 |
30 |
31 |
32 | );
33 | }
34 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/exa/tools/research_paper_search/client.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { BookOpen } from "lucide-react";
3 |
4 | import type { baseResearchPaperSearchTool } from "./base";
5 | import type { ClientToolConfig } from "@/toolkits/types";
6 | import { ToolCallDisplay, ResultsList } from "../../components";
7 |
8 | export const exaResearchPaperSearchToolConfigClient: ClientToolConfig<
9 | typeof baseResearchPaperSearchTool.inputSchema.shape,
10 | typeof baseResearchPaperSearchTool.outputSchema.shape
11 | > = {
12 | CallComponent: ({ args }) => {
13 | return (
14 |
19 | );
20 | },
21 | ResultComponent: ({ result }) => {
22 | return (
23 |
29 | );
30 | },
31 | };
32 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/google-calendar/tools/find-availability/server.ts:
--------------------------------------------------------------------------------
1 | import { type findAvailabilityTool } from "./base";
2 | import type { ServerToolConfig } from "@/toolkits/types";
3 | import type { Client } from "@notionhq/client";
4 | import type { calendar_v3 } from "googleapis";
5 | import { analyzeAvailability } from "./lib";
6 |
7 | export const googleCalendarFindAvailabilityToolConfigServer = (
8 | calendar: calendar_v3.Calendar,
9 | notion: Client,
10 | ): ServerToolConfig<
11 | typeof findAvailabilityTool.inputSchema.shape,
12 | typeof findAvailabilityTool.outputSchema.shape
13 | > => {
14 | return {
15 | message:
16 | "The user is shown available time slots in an organized grid. Give a brief summary of the availability found and ask if they would like to schedule a meeting for any of the suggested times. If defaults were used (60-minute duration, 7-day search, 9 AM-5 PM), mention this briefly.",
17 | callback: async (params) => {
18 | return await analyzeAvailability(params, calendar, notion);
19 | },
20 | };
21 | };
22 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | /* Base Options: */
4 | "esModuleInterop": true,
5 | "skipLibCheck": true,
6 | "target": "es2022",
7 | "allowJs": true,
8 | "resolveJsonModule": true,
9 | "moduleDetection": "force",
10 | "isolatedModules": true,
11 | "verbatimModuleSyntax": true,
12 |
13 | /* Strictness */
14 | "strict": true,
15 | "noUncheckedIndexedAccess": true,
16 | "checkJs": true,
17 |
18 | /* Bundled projects */
19 | "lib": ["dom", "dom.iterable", "ES2022"],
20 | "noEmit": true,
21 | "module": "ESNext",
22 | "moduleResolution": "Bundler",
23 | "jsx": "preserve",
24 | "plugins": [{ "name": "next" }],
25 | "incremental": true,
26 |
27 | /* Path Aliases */
28 | "baseUrl": ".",
29 | "paths": {
30 | "@/*": ["./src/*"]
31 | }
32 | },
33 | "include": [
34 | "next-env.d.ts",
35 | "**/*.ts",
36 | "**/*.tsx",
37 | "**/*.cjs",
38 | "**/*.js",
39 | ".next/types/**/*.ts"
40 | ],
41 | "exclude": ["node_modules"]
42 | }
43 |
--------------------------------------------------------------------------------
/src/components/ui/input.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 |
3 | import { cn } from "@/lib/utils";
4 |
5 | function Input({ className, type, ...props }: React.ComponentProps<"input">) {
6 | return (
7 |
18 | );
19 | }
20 |
21 | export { Input };
22 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/google-calendar/components/tool-call.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { HStack, VStack } from "@/components/ui/stack";
3 | import { Search } from "lucide-react";
4 |
5 | interface ToolCallComponentProps {
6 | action: string;
7 | primaryText: string;
8 | secondaryText?: string;
9 | icon?: React.ComponentType<{ className?: string }>;
10 | }
11 |
12 | export const ToolCallComponent: React.FC = ({
13 | action,
14 | primaryText,
15 | secondaryText,
16 | icon: Icon = Search,
17 | }) => {
18 | return (
19 |
20 |
21 |
22 |
23 | {action}
24 |
25 | {primaryText}
26 | {secondaryText && (
27 | {secondaryText}
28 | )}
29 |
30 |
31 | );
32 | };
33 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/google-drive/components/tool-call.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { HStack, VStack } from "@/components/ui/stack";
3 | import { Search } from "lucide-react";
4 |
5 | interface ToolCallComponentProps {
6 | action: string;
7 | primaryText: string;
8 | secondaryText?: string;
9 | icon?: React.ComponentType<{ className?: string }>;
10 | }
11 |
12 | export const ToolCallComponent: React.FC = ({
13 | action,
14 | primaryText,
15 | secondaryText,
16 | icon: Icon = Search,
17 | }) => {
18 | return (
19 |
20 |
21 |
22 |
23 | {action}
24 |
25 | {primaryText}
26 | {secondaryText && (
27 | {secondaryText}
28 | )}
29 |
30 |
31 | );
32 | };
33 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/twitter/tools/profile/server.ts:
--------------------------------------------------------------------------------
1 | import type { ServerToolConfig } from "@/toolkits/types";
2 | import type { getUserProfileTool } from "./base";
3 | import type { TwitterApi } from "twitter-api-v2";
4 |
5 | export const getUserProfileToolConfigServer = (
6 | client: TwitterApi,
7 | ): ServerToolConfig<
8 | typeof getUserProfileTool.inputSchema.shape,
9 | typeof getUserProfileTool.outputSchema.shape
10 | > => {
11 | return {
12 | callback: async (args: { username: string }) => {
13 | const { username } = args;
14 |
15 | const user = await client.v2.userByUsername(username, {
16 | "user.fields": [
17 | "description",
18 | "location",
19 | "url",
20 | "public_metrics",
21 | "verified_type",
22 | "profile_image_url",
23 | "created_at",
24 | ],
25 | });
26 |
27 | if (!user.data) {
28 | throw new Error(`User ${username} not found`);
29 | }
30 |
31 | return {
32 | user,
33 | };
34 | },
35 | };
36 | };
37 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/google-calendar/tools/get-calendar/client.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { type getCalendarTool } from "./base";
3 | import type { ClientToolConfig } from "@/toolkits/types";
4 | import { VStack } from "@/components/ui/stack";
5 | import { CalendarCard } from "../../components/calendar-card";
6 | import { ToolCallComponent } from "../../components/tool-call";
7 |
8 | export const googleCalendarGetCalendarToolConfigClient: ClientToolConfig<
9 | typeof getCalendarTool.inputSchema.shape,
10 | typeof getCalendarTool.outputSchema.shape
11 | > = {
12 | CallComponent: ({ args }) => {
13 | return (
14 |
18 | );
19 | },
20 | ResultComponent: ({ result }) => {
21 | return (
22 |
23 | Calendar Details
24 |
25 |
26 | );
27 | },
28 | };
29 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/strava/tools/explore-segments/server.ts:
--------------------------------------------------------------------------------
1 | import type { Strava } from "strava";
2 |
3 | import type { ServerToolConfig } from "@/toolkits/types";
4 |
5 | import type { exploreSegmentsBase } from "./base";
6 |
7 | export const exploreSegmentsToolConfigServer = (
8 | strava: Strava,
9 | ): ServerToolConfig<
10 | typeof exploreSegmentsBase.inputSchema.shape,
11 | typeof exploreSegmentsBase.outputSchema.shape
12 | > => {
13 | return {
14 | callback: async ({ bounds, activity_type }) => {
15 | const { segments: explorerSegments } =
16 | await strava.segments.exploreSegments({
17 | bounds,
18 | // @ts-expect-error - typo in strava library
19 | activity_type: activity_type,
20 | });
21 |
22 | const segments = await Promise.all(
23 | explorerSegments.map((segment) =>
24 | strava.segments.getSegmentById({ id: segment.id }),
25 | ),
26 | );
27 |
28 | return { segments };
29 | },
30 | message: "Successfully searched segments from Strava.",
31 | };
32 | };
33 |
--------------------------------------------------------------------------------
/src/ai/language/models/deepseek.ts:
--------------------------------------------------------------------------------
1 | import {
2 | type LanguageModel,
3 | LanguageModelCapability,
4 | } from "@/ai/language/types";
5 |
6 | const deepseekModelData: Omit[] = [
7 | {
8 | name: "DeepSeek R1",
9 | modelId: "deepseek-r1-0528",
10 | description:
11 | "DeepSeek R1 is a large language model optimized for various natural language processing tasks",
12 | capabilities: [],
13 | bestFor: ["General purpose", "Text generation", "Conversation"],
14 | contextLength: 131072,
15 | },
16 | {
17 | name: "DeepSeek 3",
18 | modelId: "deepseek-chat-v3-0324",
19 | description:
20 | "DeepSeek 3 is the latest generation of DeepSeek models with enhanced capabilities",
21 | capabilities: [LanguageModelCapability.ToolCalling],
22 | bestFor: ["Advanced reasoning", "Code generation", "Creative writing"],
23 | contextLength: 131072,
24 | },
25 | ];
26 |
27 | export const deepseekModels: LanguageModel[] = deepseekModelData.map(
28 | (model) => ({
29 | ...model,
30 | provider: "deepseek",
31 | }),
32 | );
33 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/google-calendar/base.ts:
--------------------------------------------------------------------------------
1 | import type { ToolkitConfig } from "@/toolkits/types";
2 | import { z } from "zod";
3 | import { GoogleCalendarTools } from "./tools";
4 | import {
5 | listCalendarsTool,
6 | getCalendarTool,
7 | listEventsTool,
8 | getEventTool,
9 | searchEventsTool,
10 | createEventTool,
11 | findAvailabilityTool,
12 | } from "./tools";
13 |
14 | export const googleCalendarParameters = z.object({});
15 |
16 | export const baseGoogleCalendarToolkitConfig: ToolkitConfig<
17 | GoogleCalendarTools,
18 | typeof googleCalendarParameters.shape
19 | > = {
20 | tools: {
21 | [GoogleCalendarTools.ListCalendars]: listCalendarsTool,
22 | [GoogleCalendarTools.GetCalendar]: getCalendarTool,
23 | [GoogleCalendarTools.ListEvents]: listEventsTool,
24 | [GoogleCalendarTools.GetEvent]: getEventTool,
25 | [GoogleCalendarTools.SearchEvents]: searchEventsTool,
26 | [GoogleCalendarTools.CreateEvent]: createEventTool,
27 | [GoogleCalendarTools.FindAvailability]: findAvailabilityTool,
28 | },
29 | parameters: googleCalendarParameters,
30 | };
31 |
--------------------------------------------------------------------------------
/prisma/migrations/20250721030057_tools_and_toolkiits/migration.sql:
--------------------------------------------------------------------------------
1 | /*
2 | Warnings:
3 |
4 | - You are about to drop the `ToolUsage` table. If the table is not empty, all the data it contains will be lost.
5 |
6 | */
7 | -- DropTable
8 | DROP TABLE "ToolUsage";
9 |
10 | -- CreateTable
11 | CREATE TABLE "Toolkit" (
12 | "id" TEXT NOT NULL,
13 | "name" TEXT NOT NULL,
14 | "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
15 | "updatedAt" TIMESTAMP(3) NOT NULL,
16 |
17 | CONSTRAINT "Toolkit_pkey" PRIMARY KEY ("id")
18 | );
19 |
20 | -- CreateTable
21 | CREATE TABLE "Tool" (
22 | "id" TEXT NOT NULL,
23 | "name" TEXT NOT NULL,
24 | "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
25 | "updatedAt" TIMESTAMP(3) NOT NULL,
26 | "toolkitId" TEXT NOT NULL,
27 | "usageCount" INTEGER NOT NULL DEFAULT 0,
28 |
29 | CONSTRAINT "Tool_pkey" PRIMARY KEY ("id")
30 | );
31 |
32 | -- AddForeignKey
33 | ALTER TABLE "Tool" ADD CONSTRAINT "Tool_toolkitId_fkey" FOREIGN KEY ("toolkitId") REFERENCES "Toolkit"("id") ON DELETE CASCADE ON UPDATE CASCADE;
34 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/e2b/client.tsx:
--------------------------------------------------------------------------------
1 | import { Terminal } from "lucide-react";
2 |
3 | import { Link } from "../components/link";
4 |
5 | import { E2BTools } from "./tools/tools";
6 | import { createClientToolkit } from "@/toolkits/create-toolkit";
7 | import { e2bRunCodeToolConfigClient } from "./tools/run_code/client";
8 | import { baseE2BToolkitConfig } from "./base";
9 | import { ToolkitGroups } from "@/toolkits/types";
10 |
11 | export const e2bClientToolkit = createClientToolkit(
12 | baseE2BToolkitConfig,
13 | {
14 | name: "Code Interpreter",
15 | description: "Execute python code in a secure environment",
16 | icon: Terminal,
17 | form: null,
18 | type: ToolkitGroups.Native,
19 | envVars: [
20 | {
21 | type: "all",
22 | keys: ["E2B_API_KEY"],
23 | description: (
24 |
25 | Get an E2B API Key{" "}
26 | here
27 |
28 | ),
29 | },
30 | ],
31 | },
32 | {
33 | [E2BTools.RunCode]: e2bRunCodeToolConfigClient,
34 | },
35 | );
36 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/google-calendar/tools/get-event/client.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { type getEventTool } from "./base";
3 | import type { ClientToolConfig } from "@/toolkits/types";
4 | import { VStack } from "@/components/ui/stack";
5 | import { EventCard } from "../../components/event-card";
6 | import { ToolCallComponent } from "../../components/tool-call";
7 |
8 | export const googleCalendarGetEventToolConfigClient: ClientToolConfig<
9 | typeof getEventTool.inputSchema.shape,
10 | typeof getEventTool.outputSchema.shape
11 | > = {
12 | CallComponent: ({ args }) => {
13 | return (
14 |
19 | );
20 | },
21 | ResultComponent: ({ result }) => {
22 | return (
23 |
24 | Event Details
25 |
26 |
27 | );
28 | },
29 | };
30 |
--------------------------------------------------------------------------------
/src/app/_components/navbar/index.tsx:
--------------------------------------------------------------------------------
1 | import Link from "next/link";
2 |
3 | import { AccountButton } from "./account-button";
4 | import { ColorModeToggle } from "./color-mode-toggle";
5 | import { HStack } from "@/components/ui/stack";
6 | import { auth } from "@/server/auth";
7 | import { SidebarTrigger } from "@/components/ui/sidebar";
8 | import { Menu } from "lucide-react";
9 |
10 | export const Navbar = async () => {
11 | const session = await auth();
12 |
13 | if (!session) return null;
14 |
15 | return (
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | Toolkit.dev
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | );
33 | };
34 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/notion/base.ts:
--------------------------------------------------------------------------------
1 | import type { ToolkitConfig } from "@/toolkits/types";
2 | import { z } from "zod";
3 | import { NotionTools } from "./tools";
4 | import {
5 | listDatabasesTool,
6 | queryDatabaseTool,
7 | createDatabaseTool,
8 | getPageTool,
9 | searchPagesTool,
10 | createPageTool,
11 | getBlocksTool,
12 | appendBlocksTool,
13 | listUsersTool,
14 | } from "./tools";
15 |
16 | export const notionParameters = z.object({});
17 |
18 | export const baseNotionToolkitConfig: ToolkitConfig<
19 | NotionTools,
20 | typeof notionParameters.shape
21 | > = {
22 | tools: {
23 | [NotionTools.ListDatabases]: listDatabasesTool,
24 | [NotionTools.QueryDatabase]: queryDatabaseTool,
25 | [NotionTools.CreateDatabase]: createDatabaseTool,
26 | [NotionTools.GetPage]: getPageTool,
27 | [NotionTools.SearchPages]: searchPagesTool,
28 | [NotionTools.CreatePage]: createPageTool,
29 | [NotionTools.GetBlocks]: getBlocksTool,
30 | [NotionTools.AppendBlocks]: appendBlocksTool,
31 | [NotionTools.ListUsers]: listUsersTool,
32 | },
33 | parameters: notionParameters,
34 | };
35 |
--------------------------------------------------------------------------------
/src/app/(general)/account/components/header.tsx:
--------------------------------------------------------------------------------
1 | import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
2 | import type { User } from "@prisma/client";
3 |
4 | interface Props {
5 | user: User;
6 | }
7 |
8 | export const AccountHeader: React.FC = ({ user }) => {
9 | return (
10 |
11 |
12 |
13 |
14 |
15 | {(user.name ?? user.email)?.charAt(0).toUpperCase() ?? "?"}
16 |
17 |
18 |
19 | {user.name &&
{user.name}
}
20 | {user.email && (
21 |
{user.email}
22 | )}
23 | {!user.name && !user.email && (
24 |
No name or email
25 | )}
26 |
27 |
28 |
29 | );
30 | };
31 |
--------------------------------------------------------------------------------
/src/components/ui/info-tooltip.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | import {
4 | Tooltip,
5 | TooltipContent,
6 | TooltipProvider,
7 | TooltipTrigger,
8 | } from "@/components/ui/tooltip";
9 | import { cn } from "@/lib/utils";
10 | import { Info } from "lucide-react";
11 |
12 | interface Props {
13 | content: string;
14 | className?: string;
15 | contentClassName?: string;
16 | }
17 |
18 | export const InfoTooltip: React.FC = ({
19 | content,
20 | className,
21 | contentClassName,
22 | }) => (
23 |
24 |
25 |
26 |
32 |
33 |
34 |
35 |
39 | {content}
40 |
41 |
42 |
43 | );
44 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2025 Jason Hedman
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/prisma/migrations/20250608175206_chats/migration.sql:
--------------------------------------------------------------------------------
1 | -- CreateEnum
2 | CREATE TYPE "Visibility" AS ENUM ('public', 'private');
3 |
4 | -- CreateTable
5 | CREATE TABLE "Chat" (
6 | "id" TEXT NOT NULL,
7 | "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
8 | "title" TEXT NOT NULL,
9 | "userId" TEXT NOT NULL,
10 | "visibility" "Visibility" NOT NULL DEFAULT 'private',
11 |
12 | CONSTRAINT "Chat_pkey" PRIMARY KEY ("id")
13 | );
14 |
15 | -- CreateTable
16 | CREATE TABLE "Message" (
17 | "id" TEXT NOT NULL,
18 | "chatId" TEXT NOT NULL,
19 | "role" TEXT NOT NULL,
20 | "parts" JSONB NOT NULL,
21 | "attachments" JSONB NOT NULL,
22 | "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
23 |
24 | CONSTRAINT "Message_pkey" PRIMARY KEY ("id")
25 | );
26 |
27 | -- AddForeignKey
28 | ALTER TABLE "Chat" ADD CONSTRAINT "Chat_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
29 |
30 | -- AddForeignKey
31 | ALTER TABLE "Message" ADD CONSTRAINT "Message_chatId_fkey" FOREIGN KEY ("chatId") REFERENCES "Chat"("id") ON DELETE CASCADE ON UPDATE CASCADE;
32 |
--------------------------------------------------------------------------------
/src/app/manifest.ts:
--------------------------------------------------------------------------------
1 | import type { MetadataRoute } from "next";
2 |
3 | export default function manifest(): MetadataRoute.Manifest {
4 | return {
5 | name: "Toolkit.dev",
6 | short_name: "Toolkit.dev",
7 | description: "The Playground for LLM Tool Developers",
8 | start_url: "/",
9 | display: "standalone",
10 | background_color: "#4299e1",
11 | theme_color: "#4299e1",
12 | icons: [
13 | {
14 | src: "/manifest/web-app-manifest-192x192.png",
15 | sizes: "192x192",
16 | type: "image/png",
17 | purpose: "any",
18 | },
19 | {
20 | src: "/manifest/web-app-manifest-192x192.png",
21 | sizes: "192x192",
22 | type: "image/png",
23 | purpose: "maskable",
24 | },
25 | {
26 | src: "/manifest/web-app-manifest-512x512.png",
27 | sizes: "512x512",
28 | type: "image/png",
29 | purpose: "any",
30 | },
31 | {
32 | src: "/manifest/web-app-manifest-512x512.png",
33 | sizes: "512x512",
34 | type: "image/png",
35 | purpose: "maskable",
36 | },
37 | ],
38 | };
39 | }
40 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/google-calendar/tools/list-events/server.ts:
--------------------------------------------------------------------------------
1 | import { type listEventsTool } from "./base";
2 | import type { ServerToolConfig } from "@/toolkits/types";
3 | import { fetchEvents } from "../../lib";
4 | import type { calendar_v3 } from "googleapis";
5 |
6 | export const googleCalendarListEventsToolConfigServer = (
7 | calendar: calendar_v3.Calendar,
8 | ): ServerToolConfig<
9 | typeof listEventsTool.inputSchema.shape,
10 | typeof listEventsTool.outputSchema.shape
11 | > => {
12 | return {
13 | callback: async ({
14 | calendarId,
15 | timeMin,
16 | timeMax,
17 | maxResults,
18 | pageToken,
19 | orderBy,
20 | singleEvents,
21 | }) => {
22 | const result = await fetchEvents(calendar, {
23 | calendarId,
24 | timeMin,
25 | timeMax,
26 | maxResults: maxResults || 5,
27 | pageToken,
28 | orderBy,
29 | singleEvents,
30 | });
31 |
32 | return {
33 | events: result.events,
34 | nextPageToken: result.nextPageToken,
35 | timeZone: result.timeZone,
36 | };
37 | },
38 | };
39 | };
40 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/strava/base.ts:
--------------------------------------------------------------------------------
1 | import { z } from "zod";
2 |
3 | import { StravaTools } from "./tools";
4 |
5 | import {
6 | getAthleteBase,
7 | getActivityDetailsBase,
8 | getActivitiesBase,
9 | getAthleteStatsBase,
10 | getAthleteZonesBase,
11 | getRoutesBase,
12 | getSegmentDetailsBase,
13 | exploreSegmentsBase,
14 | } from "./tools";
15 |
16 | import type { ToolkitConfig } from "@/toolkits/types";
17 |
18 | export const stravaParameters = z.object({});
19 |
20 | export const baseStravaToolkitConfig: ToolkitConfig<
21 | StravaTools,
22 | typeof stravaParameters.shape
23 | > = {
24 | tools: {
25 | [StravaTools.GetAthleteProfile]: getAthleteBase,
26 | [StravaTools.GetAthleteActivities]: getActivitiesBase,
27 | [StravaTools.GetActivityDetails]: getActivityDetailsBase,
28 | [StravaTools.GetAthleteStats]: getAthleteStatsBase,
29 | [StravaTools.ExploreSegments]: exploreSegmentsBase,
30 | [StravaTools.GetSegmentDetails]: getSegmentDetailsBase,
31 | [StravaTools.GetRoutes]: getRoutesBase,
32 | [StravaTools.GetAthleteZones]: getAthleteZonesBase,
33 | },
34 | parameters: stravaParameters,
35 | };
36 |
--------------------------------------------------------------------------------
/src/app/(general)/workbench/[id]/_components/header.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { ToolkitIcons } from "@/components/toolkit/toolkit-icons";
4 | import { Button } from "@/components/ui/button";
5 | import { HStack } from "@/components/ui/stack";
6 | import type { Toolkits } from "@/toolkits/toolkits/shared";
7 | import type { Workbench } from "@prisma/client";
8 | import { Settings, Anvil } from "lucide-react";
9 | import Link from "next/link";
10 |
11 | interface WorkbenchHeaderProps {
12 | workbench: Workbench;
13 | }
14 |
15 | export function WorkbenchHeader({ workbench }: WorkbenchHeaderProps) {
16 | return (
17 |
18 |
19 |
20 | {workbench.name}
21 |
22 |
23 |
24 |
27 |
28 |
29 | );
30 | }
31 |
--------------------------------------------------------------------------------
/src/server/api/routers/credits.ts:
--------------------------------------------------------------------------------
1 | import { createTRPCRouter, protectedProcedure } from "@/server/api/trpc";
2 |
3 | import { env } from "@/env";
4 |
5 | import { IS_DEVELOPMENT } from "@/lib/constants";
6 |
7 | export const creditsRouter = createTRPCRouter({
8 | getAvailableCredits: protectedProcedure.query(async () => {
9 | if (!IS_DEVELOPMENT) {
10 | return {
11 | totalCredits: 0,
12 | totalUsage: 0,
13 | };
14 | }
15 |
16 | if (!env.OPENROUTER_API_KEY) {
17 | throw new Error("OPENROUTER_API_KEY is not set");
18 | }
19 |
20 | const response = await fetch("https://openrouter.ai/api/v1/credits", {
21 | headers: {
22 | "Content-Type": "application/json",
23 | Authorization: `Bearer ${env.OPENROUTER_API_KEY}`,
24 | },
25 | });
26 |
27 | const {
28 | data: { total_credits, total_usage },
29 | } = (await response.json()) as {
30 | data: {
31 | total_credits: number;
32 | total_usage: number;
33 | };
34 | };
35 |
36 | return {
37 | totalCredits: total_credits,
38 | totalUsage: total_usage,
39 | };
40 | }),
41 | });
42 |
--------------------------------------------------------------------------------
/src/app/api/trpc/[trpc]/route.ts:
--------------------------------------------------------------------------------
1 | import { fetchRequestHandler } from "@trpc/server/adapters/fetch";
2 | import { type NextRequest } from "next/server";
3 |
4 | import { env } from "@/env";
5 | import { appRouter } from "@/server/api/root";
6 | import { createTRPCContext } from "@/server/api/trpc";
7 |
8 | /**
9 | * This wraps the `createTRPCContext` helper and provides the required context for the tRPC API when
10 | * handling a HTTP request (e.g. when you make requests from Client Components).
11 | */
12 | const createContext = async (req: NextRequest) => {
13 | return createTRPCContext({
14 | headers: req.headers,
15 | });
16 | };
17 |
18 | const handler = (req: NextRequest) =>
19 | fetchRequestHandler({
20 | endpoint: "/api/trpc",
21 | req,
22 | router: appRouter,
23 | createContext: () => createContext(req),
24 | onError:
25 | env.NODE_ENV === "development"
26 | ? ({ path, error }) => {
27 | console.error(
28 | `❌ tRPC failed on ${path ?? ""}: ${error.message}`,
29 | );
30 | }
31 | : undefined,
32 | });
33 |
34 | export { handler as GET, handler as POST };
35 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/exa/tools/crawling/server.ts:
--------------------------------------------------------------------------------
1 | import { type baseCrawlingTool } from "./base";
2 | import { env } from "@/env";
3 | import { Exa } from "exa-js";
4 | import type { ServerToolConfig } from "@/toolkits/types";
5 |
6 | export const exaCrawlingToolConfigServer: ServerToolConfig<
7 | typeof baseCrawlingTool.inputSchema.shape,
8 | typeof baseCrawlingTool.outputSchema.shape
9 | > = {
10 | callback: async ({ urls }) => {
11 | if (!env.EXA_API_KEY) {
12 | throw new Error("EXA_API_KEY is not set");
13 | }
14 |
15 | const exa = new Exa(env.EXA_API_KEY);
16 |
17 | const { results } = await exa.getContents(urls);
18 |
19 | return {
20 | results: results.map((result) => ({
21 | title: result.title,
22 | url: result.url,
23 | content: result.text,
24 | publishedDate: result.publishedDate,
25 | image: result.image,
26 | favicon: result.favicon,
27 | score: result.score,
28 | author: result.author,
29 | })),
30 | };
31 | },
32 | message:
33 | "The user is shown the extracted content from the URL. Provide a brief summary of what was found.",
34 | };
35 |
--------------------------------------------------------------------------------
/src/toolkits/toolkits/spotify/tools/tracks/server.ts:
--------------------------------------------------------------------------------
1 | import type { SpotifyApi } from "@spotify/web-api-ts-sdk";
2 |
3 | import type { ServerToolConfig } from "@/toolkits/types";
4 | import type { getTracksBase } from "@/toolkits/toolkits/spotify/tools/tracks/base";
5 |
6 | export const getTracksToolConfigServer = (
7 | spotify: SpotifyApi,
8 | ): ServerToolConfig<
9 | typeof getTracksBase.inputSchema.shape,
10 | typeof getTracksBase.outputSchema.shape
11 | > => {
12 | return {
13 | callback: async ({ offset = 0 }) => {
14 | try {
15 | const { items } = await spotify.currentUser.tracks.savedTracks(
16 | 10,
17 | offset,
18 | );
19 | return {
20 | tracks: items,
21 | };
22 | } catch (error) {
23 | console.error("Spotify API error:", error);
24 | throw new Error("Failed to fetch tracks from Spotify");
25 | }
26 | },
27 | message:
28 | "Successfully retrieved playlists from your Spotify account. The user is shown the responses in the UI. Do not reiterate them. If you called this tool because the user asked a question, answer the question.",
29 | };
30 | };
31 |
--------------------------------------------------------------------------------
/src/components/ui/code/codegen.ts:
--------------------------------------------------------------------------------
1 | import { codegen } from "shiki-codegen";
2 |
3 | import * as fs from "fs";
4 | import * as path from "path";
5 | import { fileURLToPath } from "url";
6 |
7 | const __filename = fileURLToPath(import.meta.url);
8 | const __dirname = path.dirname(__filename);
9 |
10 | const { code } = await codegen({
11 | langs: [
12 | "typescript",
13 | "javascript",
14 | "python",
15 | "java",
16 | "c",
17 | "csharp",
18 | "cpp",
19 | "go",
20 | "rust",
21 | "php",
22 | "ruby",
23 | "swift",
24 | "kotlin",
25 | "dart",
26 | "scala",
27 | "r",
28 | "matlab",
29 | "sql",
30 | "html",
31 | "css",
32 | "vue",
33 | "jsx",
34 | "tsx",
35 | "json",
36 | "yaml",
37 | "markdown",
38 | "bash",
39 | "powershell",
40 | "docker",
41 | "terraform",
42 | "graphql",
43 | "solidity",
44 | "svelte",
45 | "astro",
46 | ],
47 | themes: ["github-light", "github-dark"],
48 | engine: "javascript",
49 | typescript: true,
50 | });
51 |
52 | const outputPath = path.join(__dirname, "shiki.bundle.ts");
53 | fs.writeFileSync(outputPath, code);
54 |
--------------------------------------------------------------------------------
/src/server/api/routers/streams.ts:
--------------------------------------------------------------------------------
1 | import { z } from "zod";
2 |
3 | import { createTRPCRouter, protectedProcedure } from "@/server/api/trpc";
4 |
5 | export const streamsRouter = createTRPCRouter({
6 | createStreamId: protectedProcedure
7 | .input(
8 | z.object({
9 | streamId: z.string(),
10 | chatId: z.string(),
11 | }),
12 | )
13 | .mutation(async ({ ctx, input }) => {
14 | return await ctx.db.stream.create({
15 | data: {
16 | id: input.streamId,
17 | chatId: input.chatId,
18 | createdAt: new Date(),
19 | },
20 | });
21 | }),
22 |
23 | getStreamIdsByChatId: protectedProcedure
24 | .input(
25 | z.object({
26 | chatId: z.string(),
27 | }),
28 | )
29 | .query(async ({ ctx, input }) => {
30 | const streams = await ctx.db.stream.findMany({
31 | where: {
32 | chatId: input.chatId,
33 | },
34 | orderBy: {
35 | createdAt: "asc",
36 | },
37 | select: {
38 | id: true,
39 | },
40 | });
41 |
42 | return streams.map((stream) => stream.id);
43 | }),
44 | });
45 |
--------------------------------------------------------------------------------
/src/app/(general)/_components/landing-page/workbench-examples/data.tsx:
--------------------------------------------------------------------------------
1 | import { Toolkits } from "@/toolkits/toolkits/shared";
2 | import type { WorkbenchExample } from "./types";
3 | import { BarChart3, Code, Briefcase } from "lucide-react";
4 |
5 | export const workbenchExamples: WorkbenchExample[] = [
6 | {
7 | title: "Repo Researcher",
8 | systemPrompt:
9 | "Find the latest trending repositories each day, research the company behind each, and store a writeup in my Notion database.",
10 | toolkits: [Toolkits.Exa, Toolkits.Github, Toolkits.Notion],
11 | icon: Code,
12 | },
13 | {
14 | title: "Data Analyst",
15 | systemPrompt:
16 | "Collects financial data on provided tickers from Yahoo Finance, calculates trends, and stores visualizations in my Google Drive.",
17 | toolkits: [Toolkits.E2B, Toolkits.Memory, Toolkits.GoogleDrive],
18 | icon: BarChart3,
19 | },
20 | {
21 | title: "Project Manager",
22 | systemPrompt:
23 | "Find availability on my Google Calendar to meet with the members of my Notion Workspace.",
24 | toolkits: [Toolkits.GoogleCalendar, Toolkits.Notion, Toolkits.Memory],
25 | icon: Briefcase,
26 | },
27 | ];
28 |
--------------------------------------------------------------------------------
/src/toolkits/create-tool.ts:
--------------------------------------------------------------------------------
1 | import type { ZodObject, ZodRawShape } from "zod";
2 | import type {
3 | BaseTool,
4 | ClientTool,
5 | ClientToolConfig,
6 | ServerTool,
7 | ServerToolConfig,
8 | } from "./types";
9 |
10 | export const createBaseTool = <
11 | Args extends ZodRawShape,
12 | Output extends ZodRawShape,
13 | >({
14 | description,
15 | inputSchema,
16 | outputSchema,
17 | }: {
18 | description: string;
19 | inputSchema: ZodObject;
20 | outputSchema: ZodObject