Skip to content

Ian/playground UI #41

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: ian/apikeys-files-beforemessageid
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 25 additions & 8 deletions .cursor/rules/convex_rules.mdc
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
description: Guidelines and best practices for building Convex projects, including database schema design, queries, mutations, and real-world examples
globs: **/*.{ts,tsx,js,jsx}
globs: **/*.ts,**/*.tsx,**/*.js,**/*.jsx
alwaysApply: false
---

# Convex guidelines
Expand Down Expand Up @@ -85,6 +86,19 @@ globs: **/*.{ts,tsx,js,jsx}
},
});
```
- Here are the valid Convex types along with their respective validators:
Convex Type | TS/JS type | Example Usage | Validator for argument validation and schemas | Notes |
| ----------- | ------------| -----------------------| -----------------------------------------------| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Id | string | `doc._id` | `v.id(tableName)` | |
| Null | null | `null` | `v.null()` | JavaScript's `undefined` is not a valid Convex value. Functions the return `undefined` or do not return will return `null` when called from a client. Use `null` instead. |
| Int64 | bigint | `3n` | `v.int64()` | Int64s only support BigInts between -2^63 and 2^63-1. Convex supports `bigint`s in most modern browsers. |
| Float64 | number | `3.1` | `v.number()` | Convex supports all IEEE-754 double-precision floating point numbers (such as NaNs). Inf and NaN are JSON serialized as strings. |
| Boolean | boolean | `true` | `v.boolean()` |
| String | string | `"abc"` | `v.string()` | Strings are stored as UTF-8 and must be valid Unicode sequences. Strings must be smaller than the 1MB total size limit when encoded as UTF-8. |
| Bytes | ArrayBuffer | `new ArrayBuffer(8)` | `v.bytes()` | Convex supports first class bytestrings, passed in as `ArrayBuffer`s. Bytestrings must be smaller than the 1MB total size limit for Convex types. |
| Array | Array] | `[1, 3.2, "abc"]` | `v.array(values)` | Arrays can have at most 8192 values. |
| Object | Object | `{a: "abc"}` | `v.object({property: value})` | Convex only supports "plain old JavaScript objects" (objects that do not have a custom prototype). Objects can have at most 1024 entries. Field names must be nonempty and not start with "$" or "_". |
| Record | Record | `{"a": "1", "b": "2"}` | `v.record(keys, values)` | Records are objects at runtime, but can have dynamic keys. Keys must be only ASCII characters, nonempty, and not start with "$" or "_". |

### Function registration
- Use `internalQuery`, `internalMutation`, and `internalAction` to register internal functions. These functions are private and aren't part of an app's API. They can only be called by other Convex functions. These functions are always imported from `./_generated/server`.
Expand Down Expand Up @@ -152,6 +166,9 @@ globs: **/*.{ts,tsx,js,jsx}
},
});
```
Note: `paginationOpts` is an object with the following properties:
- `numItems`: the maximum number of documents to return (the validator is `v.number()`)
- `cursor`: the cursor to use to fetch the next page of documents (the validator is `v.union(v.string(), v.null())`)
- A query that ends in `.paginate()` returns an object that has the following properties:
- page (contains an array of documents that you fetches)
- isDone (a boolean that represents whether or not this is the last page of documents)
Expand All @@ -165,7 +182,7 @@ globs: **/*.{ts,tsx,js,jsx}
## Schema guidelines
- Always define your schema in `convex/schema.ts`.
- Always import the schema definition functions from `convex/server`:
- System fields are automatically added to all documents and are prefixed with an underscore.
- System fields are automatically added to all documents and are prefixed with an underscore. The two system fields that are automatically added to all documents are `_creationTime` which has the validator `v.number()` and `_id` which has the validator `v.id(tableName)`.
- Always include all index fields in the index name. For example, if an index is defined as `["field1", "field2"]`, the index name should be "by_field1_and_field2".
- Index fields must be queried in the same order they are defined. If you want to be able to query by "field1" then "field2" and by "field2" then "field1", you must create separate indexes.

Expand Down Expand Up @@ -301,13 +318,13 @@ const messages = await ctx.db


# Examples:
## Example: thread-app
## Example: chat-app

### Task
```
Create a real-time thread application backend with AI responses. The app should:
Create a real-time chat application backend with AI responses. The app should:
- Allow creating users with names
- Support multiple thread channels
- Support multiple chat channels
- Enable users to send messages to channels
- Automatically generate AI responses to user messages
- Show recent message history
Expand All @@ -325,7 +342,7 @@ and limit history display to the 10 most recent messages per channel.

### Analysis
1. Task Requirements Summary:
- Build a real-time thread backend with AI integration
- Build a real-time chat backend with AI integration
- Support user creation
- Enable channel-based conversations
- Store and retrieve messages with proper ordering
Expand Down Expand Up @@ -414,8 +431,8 @@ Internal Functions:
#### package.json
```typescript
{
"name": "thread-app",
"description": "This example shows how to build a thread app without authentication.",
"name": "chat-app",
"description": "This example shows how to build a chat app without authentication.",
"version": "1.0.0",
"dependencies": {
"convex": "^1.17.4",
Expand Down
2 changes: 2 additions & 0 deletions example/convex/_generated/api.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import type * as example from "../example.js";
import type * as http from "../http.js";
import type * as ideaAgents from "../ideaAgents.js";
import type * as ideas from "../ideas.js";
import type * as playground from "../playground.js";
import type * as weather from "../weather.js";

import type {
Expand All @@ -33,6 +34,7 @@ declare const fullApi: ApiFromModules<{
http: typeof http;
ideaAgents: typeof ideaAgents;
ideas: typeof ideas;
playground: typeof playground;
weather: typeof weather;
}>;
declare const fullApiWithMounts: typeof fullApi;
Expand Down
4 changes: 2 additions & 2 deletions example/convex/example.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const usageHandler: UsageHandler = async (_ctx, args) => {
};

// Define an agent similarly to the AI SDK
const weatherAgent = new Agent(components.agent, {
export const weatherAgent = new Agent(components.agent, {
name: "Weather Agent",
chat: openai.chat("gpt-4o-mini"),
textEmbedding: openai.embedding("text-embedding-3-small"),
Expand All @@ -29,7 +29,7 @@ const weatherAgent = new Agent(components.agent, {
usageHandler,
});

const fashionAgent = new Agent(components.agent, {
export const fashionAgent = new Agent(components.agent, {
name: "Fashion Agent",
chat: openai.chat("gpt-4o-mini"),
textEmbedding: openai.embedding("text-embedding-3-small"),
Expand Down
23 changes: 23 additions & 0 deletions example/convex/playground.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { definePlaygroundAPI } from "@convex-dev/agent/playground";
import { components } from "./_generated/api";
import { weatherAgent, fashionAgent } from "./example";

/**
* Here we expose the API so the frontend can access it.
* Authorization is handled by passing up an apiKey that can be generated
* on the dashboard or via CLI via:
* ```
* npx convex run --component agent apiKeys:issue
* ```
*/
export const {
listAgents,
listUsers,
listThreads,
listMessages,
createThread,
generateText,
fetchPromptContext,
} = definePlaygroundAPI(components.agent, {
agents: [weatherAgent, fashionAgent],
});
7 changes: 7 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,13 @@
"default": "./dist/commonjs/client/index.js"
}
},
"./playground": {
"import": {
"@convex-dev/component-source": "./src/client/playground.ts",
"types": "./dist/esm/client/playground.d.ts",
"default": "./dist/esm/client/playground.js"
}
},
"./validators": {
"import": {
"@convex-dev/component-source": "./src/validators.ts",
Expand Down
27 changes: 27 additions & 0 deletions playground-chef/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

# Ignored for the template, you probably want to remove it:
package-lock.json
28 changes: 28 additions & 0 deletions playground-chef/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Chat Admin Interface Implementation

This is a project built with [Chef](https://chef.convex.dev) using [Convex](https://convex.dev) as its backend.

This project is connected to the Convex deployment named [`pastel-curlew-479`](https://dashboard.convex.dev/d/pastel-curlew-479).

## Project structure

The frontend code is in the `app` directory and is built with [Vite](https://vitejs.dev/).

The backend code is in the `convex` directory.

`npm run dev` will start the frontend and backend servers.

## App authentication

Chef apps use [Convex Auth](https://auth.convex.dev/) with Anonymous auth for easy sign in. You may wish to change this before deploying your app.

## Developing and deploying your app

Check out the [Convex docs](https://docs.convex.dev/) for more information on how to develop with Convex.
* If you're new to Convex, the [Overview](https://docs.convex.dev/understanding/) is a good place to start
* Check out the [Hosting and Deployment](https://docs.convex.dev/production/) docs for how to deploy your app
* Read the [Best Practices](https://docs.convex.dev/understanding/best-practices/) guide for tips on how to improve you app further

## HTTP API

User-defined http routes are defined in the `convex/router.ts` file. We split these routes into a separate file from `convex/http.ts` to allow us to prevent the LLM from modifying the authentication routes.
21 changes: 21 additions & 0 deletions playground-chef/components.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "new-york",
"rsc": false,
"tsx": true,
"tailwind": {
"config": "tailwind.config.js",
"css": "src/index.css",
"baseColor": "slate",
"cssVariables": true,
"prefix": ""
},
"aliases": {
"components": "@/components",
"utils": "@/lib/utils",
"ui": "@/components/ui",
"lib": "@/lib",
"hooks": "@/hooks"
},
"iconLibrary": "lucide"
}
77 changes: 77 additions & 0 deletions playground-chef/eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import js from "@eslint/js";
import globals from "globals";
import reactHooks from "eslint-plugin-react-hooks";
import reactRefresh from "eslint-plugin-react-refresh";
import tseslint from "typescript-eslint";

export default tseslint.config(
{
ignores: [
"dist",
"eslint.config.js",
"convex/_generated",
"postcss.config.js",
"tailwind.config.js",
"vite.config.ts",
],
},
{
extends: [
js.configs.recommended,
...tseslint.configs.recommendedTypeChecked,
],
files: ["**/*.{ts,tsx}"],
languageOptions: {
ecmaVersion: 2020,
globals: {
...globals.browser,
...globals.node,
},
parserOptions: {
project: [
"./tsconfig.node.json",
"./tsconfig.app.json",
"./convex/tsconfig.json",
],
},
},
plugins: {
"react-hooks": reactHooks,
"react-refresh": reactRefresh,
},
rules: {
...reactHooks.configs.recommended.rules,
"react-refresh/only-export-components": [
"warn",
{ allowConstantExport: true },
],
// All of these overrides ease getting into
// TypeScript, and can be removed for stricter
// linting down the line.

// Only warn on unused variables, and ignore variables starting with `_`
"@typescript-eslint/no-unused-vars": [
"warn",
{ varsIgnorePattern: "^_", argsIgnorePattern: "^_" },
],

// Allow escaping the compiler
"@typescript-eslint/ban-ts-comment": "error",

// Allow explicit `any`s
"@typescript-eslint/no-explicit-any": "off",

// START: Allow implicit `any`s
"@typescript-eslint/no-unsafe-argument": "off",
"@typescript-eslint/no-unsafe-assignment": "off",
"@typescript-eslint/no-unsafe-call": "off",
"@typescript-eslint/no-unsafe-member-access": "off",
"@typescript-eslint/no-unsafe-return": "off",
// END: Allow implicit `any`s

// Allow async functions without await
// for consistency (esp. Convex `handler`s)
"@typescript-eslint/require-await": "off",
},
},
);
16 changes: 16 additions & 0 deletions playground-chef/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="/src/index.css" />

<title>Chef</title>

<meta property="og:image" content="/og-preview.png" />
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
46 changes: 46 additions & 0 deletions playground-chef/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
"name": "flex-template",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite --open",
"lint": "tsc -p . -noEmit --pretty false && vite build"
},
"dependencies": {
"@convex-dev/agent": "../",
"@monaco-editor/react": "^4.7.0",
"@radix-ui/react-dropdown-menu": "^2.1.14",
"@radix-ui/react-icons": "^1.3.2",
"@radix-ui/react-select": "^2.2.4",
"@radix-ui/react-slot": "^1.2.2",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"dayjs": "^1.11.13",
"lucide-react": "^0.508.0",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"sonner": "^2.0.3",
"tailwind-merge": "^3.1.0"
},
"devDependencies": {
"@eslint/js": "^9.21.0",
"@types/node": "^22.13.10",
"@types/react": "^19.0.10",
"@types/react-dom": "^19.0.4",
"@vitejs/plugin-react": "^4.3.4",
"autoprefixer": "~10",
"dotenv": "^16.4.7",
"eslint": "^9.21.0",
"eslint-plugin-react-hooks": "^5.1.0",
"eslint-plugin-react-refresh": "^0.4.19",
"globals": "^15.15.0",
"npm-run-all": "^4.1.5",
"postcss": "~8",
"prettier": "^3.5.3",
"tailwindcss": "~3",
"typescript": "~5.7.2",
"typescript-eslint": "^8.24.1",
"vite": "^6.2.0"
}
}
6 changes: 6 additions & 0 deletions playground-chef/postcss.config.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
};
Loading