fix: convert starter templates from pnpm/Turborepo to flat npm projects
Flatten langgraph-python, langgraph-js, and mcp-apps starters so npm install && npm run dev works out of the box. Replace Turborepo with concurrently, move apps/* to root, update Dockerfiles, READMEs, and entrypoints. Also remove stray pnpm-lock.yaml from a2a-a2ui and ms-agent-framework-dotnet starters.
@@ -141,3 +141,8 @@ vite.config.ts.timestamp-*
|
||||
.vite/
|
||||
|
||||
next-env.d.ts
|
||||
|
||||
# lock files (keep package-lock.json for npm)
|
||||
pnpm-lock.yaml
|
||||
yarn.lock
|
||||
bun.lockb
|
||||
|
||||
@@ -3,5 +3,4 @@ node_modules
|
||||
.git
|
||||
.env
|
||||
.env.local
|
||||
apps/web/node_modules
|
||||
apps/agent/node_modules
|
||||
agent/node_modules
|
||||
|
||||
@@ -17,9 +17,6 @@ node_modules
|
||||
.next/
|
||||
/out/
|
||||
|
||||
# turbo
|
||||
.turbo
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
@@ -44,8 +41,10 @@ yarn-error.log*
|
||||
*.tsbuildinfo
|
||||
next-env.d.ts
|
||||
|
||||
# lock files
|
||||
package-lock.json
|
||||
pnpm-lock.yaml
|
||||
# lock files (keep package-lock.json for npm)
|
||||
yarn.lock
|
||||
pnpm-lock.yaml
|
||||
bun.lockb
|
||||
|
||||
# LangGraph API
|
||||
.langgraph_api
|
||||
|
||||
@@ -1,19 +1,17 @@
|
||||
# Stage 1: Build everything in monorepo
|
||||
# Stage 1: Build the Next.js frontend
|
||||
FROM node:20-slim AS builder
|
||||
|
||||
WORKDIR /app
|
||||
RUN corepack enable
|
||||
|
||||
COPY package.json pnpm-workspace.yaml pnpm-lock.yaml* ./
|
||||
COPY apps/web/package.json ./apps/web/
|
||||
COPY apps/agent/package.json ./apps/agent/
|
||||
RUN pnpm install --no-frozen-lockfile
|
||||
COPY package.json ./
|
||||
RUN npm install
|
||||
|
||||
COPY apps/ ./apps/
|
||||
COPY turbo.json ./
|
||||
COPY app/ ./app/
|
||||
COPY public/ ./public/
|
||||
COPY next.config.ts tsconfig.json postcss.config.mjs ./
|
||||
|
||||
ENV NODE_OPTIONS="--max-old-space-size=4096"
|
||||
RUN pnpm --filter web build
|
||||
RUN npx next build
|
||||
|
||||
# Stage 2: Production image
|
||||
FROM node:20-slim AS runner
|
||||
@@ -23,15 +21,13 @@ RUN npm install -g @langchain/langgraph-cli
|
||||
WORKDIR /app
|
||||
|
||||
# Next.js build artifacts
|
||||
COPY --from=builder /app/apps/web/.next ./apps/web/.next
|
||||
COPY --from=builder /app/apps/web/node_modules ./apps/web/node_modules
|
||||
COPY --from=builder /app/apps/web/package.json ./apps/web/
|
||||
COPY --from=builder /app/apps/web/public ./apps/web/public
|
||||
|
||||
# Agent code + dependencies
|
||||
COPY --from=builder /app/apps/agent ./apps/agent
|
||||
COPY --from=builder /app/.next ./.next
|
||||
COPY --from=builder /app/node_modules ./node_modules
|
||||
COPY --from=builder /app/package.json ./
|
||||
COPY --from=builder /app/public ./public
|
||||
|
||||
# Agent code + dependencies
|
||||
COPY agent/ ./agent/
|
||||
|
||||
# Copy entrypoint
|
||||
COPY entrypoint.sh ./
|
||||
|
||||
@@ -2,86 +2,78 @@
|
||||
|
||||
This is a starter template for building AI agents using [LangGraph](https://www.langchain.com/langgraph) and [CopilotKit](https://copilotkit.ai). It provides a modern Next.js application with an integrated LangGraph agent to be built on top of.
|
||||
|
||||
This project is organized as a monorepo using [Turborepo](https://turbo.build) and [pnpm workspaces](https://pnpm.io/workspaces).
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
.
|
||||
├── apps/
|
||||
│ ├── web/ # Next.js frontend application
|
||||
│ └── agent/ # LangGraph agent
|
||||
├── pnpm-workspace.yaml
|
||||
├── turbo.json
|
||||
├── app/ # Next.js App Router pages and API routes
|
||||
│ ├── page.tsx # Main page
|
||||
│ └── api/copilotkit/ # CopilotKit API route
|
||||
├── agent/ # LangGraph agent
|
||||
│ ├── src/agent.ts # Agent definition
|
||||
│ └── langgraph.json # LangGraph configuration
|
||||
├── scripts/ # Agent run scripts
|
||||
├── public/ # Static assets
|
||||
├── next.config.ts
|
||||
├── tsconfig.json
|
||||
└── package.json
|
||||
```
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Node.js 18+
|
||||
- [pnpm](https://pnpm.io/installation) 9.15.0 or later
|
||||
- OpenAI API Key (for the LangGraph agent)
|
||||
|
||||
## Getting Started
|
||||
|
||||
1. Install all dependencies (this installs everything for both apps):
|
||||
1. Install dependencies:
|
||||
|
||||
```bash
|
||||
pnpm install
|
||||
npm install
|
||||
```
|
||||
|
||||
2. Set up your OpenAI API key:
|
||||
2. Set up your environment variables:
|
||||
|
||||
```bash
|
||||
cd apps/agent
|
||||
echo "OPENAI_API_KEY=your-openai-api-key-here" > .env
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
Then edit the `.env` file and add your OpenAI API key:
|
||||
|
||||
```bash
|
||||
OPENAI_API_KEY=your-openai-api-key-here
|
||||
```
|
||||
|
||||
3. Start the development servers:
|
||||
|
||||
```bash
|
||||
pnpm dev
|
||||
npm run dev
|
||||
```
|
||||
|
||||
This will start both the Next.js app (on port 3000) and the LangGraph agent (on port 8123) using Turborepo.
|
||||
This will start both the Next.js app (on port 3000) and the LangGraph agent (on port 8123) concurrently.
|
||||
|
||||
## Available Scripts
|
||||
|
||||
All scripts use Turborepo to run tasks across the monorepo:
|
||||
|
||||
- `pnpm dev` - Starts both the web app and agent servers in development mode
|
||||
- `pnpm dev:studio` - Starts the web app and agent with LangGraph Studio UI
|
||||
- `pnpm build` - Builds all apps for production
|
||||
- `pnpm lint` - Runs linting across all apps
|
||||
|
||||
### Running Scripts for Individual Apps
|
||||
|
||||
You can also run scripts for individual apps using pnpm's filter flag:
|
||||
|
||||
```bash
|
||||
# Run dev for just the web app
|
||||
pnpm --filter web dev
|
||||
|
||||
# Run dev for just the agent
|
||||
pnpm --filter agent dev
|
||||
|
||||
# Or navigate to the app directory
|
||||
cd apps/web
|
||||
pnpm dev
|
||||
```
|
||||
- `npm run dev` - Starts both the web app and agent servers in development mode
|
||||
- `npm run dev:debug` - Starts development servers with debug logging enabled
|
||||
- `npm run dev:ui` - Starts only the Next.js UI server
|
||||
- `npm run dev:agent` - Starts only the LangGraph agent server
|
||||
- `npm run build` - Builds the Next.js application for production
|
||||
- `npm run start` - Starts the production server
|
||||
- `npm run lint` - Runs linting
|
||||
|
||||
## Customization
|
||||
|
||||
The main UI component is in `apps/web/src/app/page.tsx`. You can:
|
||||
The main UI component is in `app/page.tsx`. You can:
|
||||
|
||||
- Modify the theme colors and styling
|
||||
- Add new frontend actions
|
||||
- Utilize shared-state
|
||||
- Customize your user-interface for interacting with LangGraph
|
||||
|
||||
The LangGraph agent code is in `apps/agent/src/`.
|
||||
The LangGraph agent code is in `agent/src/`.
|
||||
|
||||
## 📚 Documentation
|
||||
## Documentation
|
||||
|
||||
- [CopilotKit Documentation](https://docs.copilotkit.ai) - Explore CopilotKit's capabilities
|
||||
- [LangGraph Documentation](https://langchain-ai.github.io/langgraph/) - Learn more about LangGraph and its features
|
||||
@@ -101,6 +93,6 @@ This project is licensed under the MIT License - see the LICENSE file for detail
|
||||
|
||||
If you see "I'm having trouble connecting to my tools", make sure:
|
||||
|
||||
1. The LangGraph agent is running on port 8000
|
||||
1. The LangGraph agent is running on port 8123
|
||||
2. Your OpenAI API key is set correctly
|
||||
3. Both servers started successfully
|
||||
|
||||
@@ -5,5 +5,5 @@
|
||||
"graphs": {
|
||||
"starterAgent": "./src/agent.ts:graph"
|
||||
},
|
||||
"env": ".env"
|
||||
"env": "../.env"
|
||||
}
|
||||
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
@@ -1,29 +0,0 @@
|
||||
{
|
||||
"name": "web",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"lint": "next lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@copilotkit/react-core": "1.52.1",
|
||||
"@copilotkit/react-ui": "1.52.1",
|
||||
"@copilotkit/runtime": "1.52.1",
|
||||
"next": "16.0.8",
|
||||
"react": "^19.2.1",
|
||||
"react-dom": "^19.2.1",
|
||||
"shiki": "^3.22.0",
|
||||
"zod": "^3.24.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/postcss": "^4",
|
||||
"@types/node": "^20",
|
||||
"@types/react": "^19",
|
||||
"@types/react-dom": "^19",
|
||||
"tailwindcss": "^4",
|
||||
"typescript": "^5"
|
||||
}
|
||||
}
|
||||
@@ -10,8 +10,8 @@ services:
|
||||
|
||||
agent:
|
||||
build:
|
||||
context: ./apps/agent
|
||||
dockerfile: ../../docker/Dockerfile.agent
|
||||
context: ./agent
|
||||
dockerfile: ../docker/Dockerfile.agent
|
||||
environment:
|
||||
- OPENAI_API_KEY=test-key-for-aimock
|
||||
- OPENAI_BASE_URL=http://aimock:4010/v1
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
# Dockerfile for the LangGraph JS agent.
|
||||
# Mirrors the user experience: pnpm install + langgraph-cli dev.
|
||||
# Mirrors the user experience: npm install + langgraph-cli dev.
|
||||
FROM node:22-alpine
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
RUN corepack enable && corepack prepare pnpm@latest --activate
|
||||
|
||||
# Copy agent package files
|
||||
COPY package.json ./
|
||||
COPY langgraph.json ./
|
||||
@@ -13,7 +11,7 @@ COPY tsconfig.json ./
|
||||
COPY src/ ./src/
|
||||
|
||||
# Install dependencies
|
||||
RUN pnpm install --no-frozen-lockfile
|
||||
RUN npm install
|
||||
|
||||
EXPOSE 8123
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Dockerfile for the LangGraph JS Next.js frontend.
|
||||
# Builds from the monorepo root so pnpm workspaces resolve correctly.
|
||||
# Builds from the project root.
|
||||
FROM node:22-alpine AS base
|
||||
|
||||
FROM base AS deps
|
||||
@@ -7,40 +7,30 @@ RUN apk add --no-cache libc6-compat
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
RUN corepack enable && corepack prepare pnpm@latest --activate
|
||||
|
||||
# Copy monorepo package files
|
||||
COPY package.json pnpm-workspace.yaml ./
|
||||
COPY apps/web/package.json ./apps/web/
|
||||
COPY apps/agent/package.json ./apps/agent/
|
||||
COPY turbo.json ./
|
||||
# Copy package file
|
||||
COPY package.json ./
|
||||
|
||||
# Install dependencies
|
||||
RUN pnpm install --no-frozen-lockfile
|
||||
RUN npm install
|
||||
|
||||
# Build stage
|
||||
FROM base AS builder
|
||||
WORKDIR /app
|
||||
|
||||
RUN corepack enable && corepack prepare pnpm@latest --activate
|
||||
|
||||
COPY --from=deps /app/node_modules ./node_modules
|
||||
COPY --from=deps /app/apps/web/node_modules ./apps/web/node_modules
|
||||
COPY --from=deps /app/apps/agent/node_modules ./apps/agent/node_modules
|
||||
|
||||
COPY . .
|
||||
|
||||
# Add standalone output + ignoreBuildErrors + turbopack root for monorepo
|
||||
# Add standalone output + ignoreBuildErrors for Docker build
|
||||
RUN node -e "\
|
||||
const fs=require('fs'); const f='apps/web/next.config.ts'; \
|
||||
const fs=require('fs'); const f='next.config.ts'; \
|
||||
let c=fs.readFileSync(f,'utf8'); \
|
||||
if(!c.includes('standalone')){c=c.replace('};',' output: \"standalone\",\n};');} \
|
||||
if(!c.includes('ignoreBuildErrors')){c=c.replace('};',' typescript: { ignoreBuildErrors: true },\n};');} \
|
||||
if(!c.includes('turbopack')){c=c.replace('};',' turbopack: { root: \"../..\" },\n};');} \
|
||||
fs.writeFileSync(f,c);"
|
||||
|
||||
ENV NODE_OPTIONS="--max-old-space-size=4096"
|
||||
RUN pnpm --filter web build
|
||||
RUN npx next build
|
||||
|
||||
# Production stage
|
||||
FROM base AS runner
|
||||
@@ -53,12 +43,12 @@ ENV HOSTNAME=0.0.0.0
|
||||
RUN addgroup --system --gid 1001 nodejs && adduser --system --uid 1001 nextjs
|
||||
|
||||
# Copy standalone build output
|
||||
COPY --from=builder /app/apps/web/public ./public
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/apps/web/.next/standalone ./
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/apps/web/.next/static ./apps/web/.next/static
|
||||
COPY --from=builder /app/public ./public
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
|
||||
|
||||
USER nextjs
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
CMD ["node", "apps/web/server.js"]
|
||||
CMD ["node", "server.js"]
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
set -e
|
||||
|
||||
# Start LangGraph agent server on port 8123
|
||||
cd /app/apps/agent
|
||||
cd /app/agent
|
||||
npx @langchain/langgraph-cli dev --port 8123 --no-browser &
|
||||
AGENT_PID=$!
|
||||
cd /app
|
||||
@@ -10,10 +10,9 @@ cd /app
|
||||
sleep 3
|
||||
|
||||
# Start Next.js frontend
|
||||
cd /app/apps/web
|
||||
cd /app
|
||||
PORT=${PORT:-3000} npx next start --port ${PORT:-3000} &
|
||||
NEXT_PID=$!
|
||||
cd /app
|
||||
|
||||
wait -n $AGENT_PID $NEXT_PID
|
||||
EXIT_CODE=$?
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
{
|
||||
"match": {},
|
||||
"response": {
|
||||
"content": "You're currently running against aimock (a mock LLM server). This response is a catch-all for requests that don't match any test fixture. To use a real LLM: (1) Add your OPENAI_API_KEY to .env, (2) Remove or unset OPENAI_BASE_URL from your environment so requests go to OpenAI instead of aimock, (3) Restart with `pnpm dev`."
|
||||
"content": "You're currently running against aimock (a mock LLM server). This response is a catch-all for requests that don't match any test fixture. To use a real LLM: (1) Add your OPENAI_API_KEY to .env, (2) Remove or unset OPENAI_BASE_URL from your environment so requests go to OpenAI instead of aimock, (3) Restart with `npm run dev`."
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -2,17 +2,35 @@
|
||||
"name": "langgraph-js-starter",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"workspaces": [
|
||||
"apps/*"
|
||||
],
|
||||
"scripts": {
|
||||
"dev": "turbo run dev",
|
||||
"build": "turbo run build",
|
||||
"lint": "turbo run lint"
|
||||
"dev": "concurrently \"npm run dev:ui\" \"npm run dev:agent\" --names ui,agent --prefix-colors blue,green --kill-others",
|
||||
"dev:debug": "LOG_LEVEL=debug npm run dev",
|
||||
"dev:ui": "next dev",
|
||||
"dev:agent": "./scripts/run-agent.sh || scripts/run-agent.bat",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"lint": "next lint",
|
||||
"install:agent": "cd agent && npm install",
|
||||
"postinstall": "npm run install:agent"
|
||||
},
|
||||
"dependencies": {
|
||||
"@copilotkit/react-core": "1.52.1",
|
||||
"@copilotkit/react-ui": "1.52.1",
|
||||
"@copilotkit/runtime": "1.52.1",
|
||||
"next": "16.0.8",
|
||||
"react": "^19.2.1",
|
||||
"react-dom": "^19.2.1",
|
||||
"shiki": "^3.22.0",
|
||||
"zod": "^3.24.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@langchain/langgraph-cli": "^1.0.4",
|
||||
"turbo": "^2.3.3"
|
||||
"@tailwindcss/postcss": "^4",
|
||||
"@types/node": "^20",
|
||||
"@types/react": "^19",
|
||||
"@types/react-dom": "^19",
|
||||
"concurrently": "^9.1.2",
|
||||
"tailwindcss": "^4",
|
||||
"typescript": "^5"
|
||||
},
|
||||
"overrides": {
|
||||
"@langchain/core": "^1.0.1",
|
||||
@@ -20,6 +38,5 @@
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
},
|
||||
"packageManager": "pnpm@9.15.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
packages:
|
||||
- "apps/*"
|
||||
|
Before Width: | Height: | Size: 391 B After Width: | Height: | Size: 391 B |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 128 B After Width: | Height: | Size: 128 B |
|
Before Width: | Height: | Size: 385 B After Width: | Height: | Size: 385 B |
@@ -0,0 +1,3 @@
|
||||
@echo off
|
||||
cd /d "%~dp0..\agent"
|
||||
npx @langchain/langgraph-cli dev --port 8123 --no-browser
|
||||
@@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
cd "$(dirname "$0")/../agent" || exit 1
|
||||
npx @langchain/langgraph-cli dev --port 8123 --no-browser
|
||||
@@ -19,7 +19,7 @@
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
"@/*": ["./*"]
|
||||
}
|
||||
},
|
||||
"include": [
|
||||
@@ -1,16 +0,0 @@
|
||||
{
|
||||
"$schema": "https://turbo.build/schema.json",
|
||||
"tasks": {
|
||||
"dev": {
|
||||
"cache": false,
|
||||
"persistent": true
|
||||
},
|
||||
"build": {
|
||||
"dependsOn": ["^build"],
|
||||
"outputs": [".next/**", "!.next/cache/**", "dist/**"]
|
||||
},
|
||||
"lint": {
|
||||
"dependsOn": ["^lint"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
node_modules
|
||||
.next
|
||||
.turbo
|
||||
.git
|
||||
.gitignore
|
||||
.env*
|
||||
@@ -10,7 +9,6 @@ node_modules
|
||||
.claude
|
||||
.worktrees
|
||||
.langgraph_api
|
||||
apps/agent/.venv
|
||||
apps/agent/__pycache__
|
||||
apps/mcp
|
||||
agent/.venv
|
||||
agent/__pycache__
|
||||
coverage
|
||||
|
||||
@@ -42,9 +42,9 @@ yarn-error.log*
|
||||
*.tsbuildinfo
|
||||
next-env.d.ts
|
||||
|
||||
# lock files
|
||||
package-lock.json
|
||||
# lock files (keep package-lock.json for npm)
|
||||
yarn.lock
|
||||
pnpm-lock.yaml
|
||||
bun.lockb
|
||||
|
||||
# LangGraph API
|
||||
@@ -53,9 +53,6 @@ bun.lockb
|
||||
# Git worktrees
|
||||
.worktrees
|
||||
|
||||
# Turbo
|
||||
.turbo
|
||||
|
||||
# Tools
|
||||
.claude
|
||||
.scratch/
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
const path = require("path");
|
||||
|
||||
/**
|
||||
* When COPILOTKIT_LOCAL is set, rewrites CopilotKit and AG-UI dependencies
|
||||
* to link against local monorepo packages instead of pulling from npm.
|
||||
*
|
||||
* Usage:
|
||||
* COPILOTKIT_LOCAL=1 pnpm install # link to local packages
|
||||
* pnpm install # install from npm (default)
|
||||
*
|
||||
* Expects the AG-UI repo to be cloned alongside CopilotKit:
|
||||
* /some/path/CopilotKit/
|
||||
* /some/path/ag-ui/
|
||||
*/
|
||||
|
||||
const COPILOTKIT_ROOT = path.resolve(__dirname, "..", "..", "..");
|
||||
const AGUI_ROOT = path.resolve(COPILOTKIT_ROOT, "..", "ag-ui");
|
||||
|
||||
const LOCAL_PACKAGES = {
|
||||
// CopilotKit
|
||||
"@copilotkit/react-core": path.join(COPILOTKIT_ROOT, "packages/react-core"),
|
||||
"@copilotkit/react-ui": path.join(COPILOTKIT_ROOT, "packages/react-ui"),
|
||||
"@copilotkit/runtime": path.join(COPILOTKIT_ROOT, "packages/runtime"),
|
||||
"@copilotkit/shared": path.join(COPILOTKIT_ROOT, "packages/shared"),
|
||||
"@copilotkit/a2ui-renderer": path.join(
|
||||
COPILOTKIT_ROOT,
|
||||
"packages/a2ui-renderer",
|
||||
),
|
||||
// AG-UI
|
||||
"@ag-ui/client": path.join(AGUI_ROOT, "sdks/typescript/packages/client"),
|
||||
"@ag-ui/core": path.join(AGUI_ROOT, "sdks/typescript/packages/core"),
|
||||
"@ag-ui/encoder": path.join(AGUI_ROOT, "sdks/typescript/packages/encoder"),
|
||||
"@ag-ui/proto": path.join(AGUI_ROOT, "sdks/typescript/packages/proto"),
|
||||
"@ag-ui/a2ui-middleware": path.join(AGUI_ROOT, "middlewares/a2ui-middleware"),
|
||||
"@ag-ui/mcp-apps-middleware": path.join(
|
||||
AGUI_ROOT,
|
||||
"middlewares/mcp-apps-middleware",
|
||||
),
|
||||
};
|
||||
|
||||
function readPackage(pkg) {
|
||||
if (process.env.COPILOTKIT_LOCAL) {
|
||||
for (const [name, localPath] of Object.entries(LOCAL_PACKAGES)) {
|
||||
if (pkg.dependencies?.[name]) {
|
||||
pkg.dependencies[name] = `link:${localPath}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
return pkg;
|
||||
}
|
||||
|
||||
module.exports = { hooks: { readPackage } };
|
||||
@@ -19,34 +19,36 @@ This uses CopilotKit's **v2 agent state pattern** where state lives in the agent
|
||||
|
||||
## Architecture
|
||||
|
||||
This is a **Turborepo monorepo** with three apps:
|
||||
This is a **flat npm project** with a Next.js frontend at the root and a Python agent in `agent/`.
|
||||
|
||||
### Repository Structure
|
||||
|
||||
```
|
||||
apps/
|
||||
├── app/ # Next.js frontend
|
||||
│ ├── src/
|
||||
│ │ ├── app/
|
||||
│ │ │ ├── page.tsx # Main page - wires up all components
|
||||
│ │ │ └── api/copilotkit/ # CopilotKit API route
|
||||
│ │ ├── components/
|
||||
│ │ │ ├── canvas/ # Todo list UI
|
||||
│ │ │ │ ├── index.tsx # Canvas container
|
||||
│ │ │ │ ├── todo-list.tsx # Todo list with columns
|
||||
│ │ │ │ ├── todo-column.tsx # Column (pending/completed)
|
||||
│ │ │ │ └── todo-card.tsx # Individual todo card
|
||||
│ │ │ ├── example-layout/ # Layout: chat + canvas side-by-side
|
||||
│ │ │ └── generative-ui/ # Example generative UI components
|
||||
│ │ └── hooks/
|
||||
│ │ ├── use-generative-ui-examples.tsx # Example CopilotKit patterns
|
||||
│ │ └── use-example-suggestions.tsx # Chat suggestions
|
||||
├── agent/ # LangGraph Python agent
|
||||
│ ├── main.py # Agent entry point
|
||||
├── src/
|
||||
│ ├── app/
|
||||
│ │ ├── page.tsx # Main page - wires up all components
|
||||
│ │ └── api/copilotkit/ # CopilotKit API route
|
||||
│ ├── components/
|
||||
│ │ ├── canvas/ # Todo list UI
|
||||
│ │ │ ├── index.tsx # Canvas container
|
||||
│ │ │ ├── todo-list.tsx # Todo list with columns
|
||||
│ │ │ ├── todo-column.tsx # Column (pending/completed)
|
||||
│ │ │ └── todo-card.tsx # Individual todo card
|
||||
│ │ ├── example-layout/ # Layout: chat + canvas side-by-side
|
||||
│ │ └── generative-ui/ # Example generative UI components
|
||||
│ └── hooks/
|
||||
│ ├── use-generative-ui-examples.tsx # Example CopilotKit patterns
|
||||
│ └── use-example-suggestions.tsx # Chat suggestions
|
||||
├── agent/ # LangGraph Python agent
|
||||
│ ├── main.py # Agent entry point
|
||||
│ └── src/
|
||||
│ ├── todos.py # Todo tools and state schema
|
||||
│ └── query.py # Example data query tool
|
||||
└── mcp/ # MCP (Model Context Protocol) integration
|
||||
│ ├── todos.py # Todo tools and state schema
|
||||
│ └── query.py # Example data query tool
|
||||
├── scripts/ # Agent setup and run scripts
|
||||
│ ├── setup-agent.sh / .bat
|
||||
│ └── run-agent.sh / .bat
|
||||
├── package.json # Root project config (npm + concurrently)
|
||||
└── next.config.ts
|
||||
```
|
||||
|
||||
## Key Pattern: Agent State with CopilotKit v2
|
||||
@@ -58,7 +60,7 @@ The todo list uses **CopilotKit v2's agent state pattern** where state lives in
|
||||
1. **Agent defines state schema and tools** (Python)
|
||||
|
||||
```python
|
||||
# apps/agent/src/todos.py
|
||||
# agent/src/todos.py
|
||||
class Todo(TypedDict):
|
||||
id: str
|
||||
title: str
|
||||
@@ -78,7 +80,7 @@ The todo list uses **CopilotKit v2's agent state pattern** where state lives in
|
||||
2. **Frontend reads from agent state**
|
||||
|
||||
```typescript
|
||||
// apps/app/src/components/canvas/index.tsx
|
||||
// src/components/canvas/index.tsx
|
||||
const { agent } = useAgent();
|
||||
|
||||
return (
|
||||
@@ -120,7 +122,7 @@ The todo list uses **CopilotKit v2's agent state pattern** where state lives in
|
||||
|
||||
### Agent Backend
|
||||
|
||||
**Agent Definition** (`apps/agent/main.py`):
|
||||
**Agent Definition** (`agent/main.py`):
|
||||
|
||||
```python
|
||||
from langchain.agents import create_agent
|
||||
@@ -136,7 +138,7 @@ agent = create_agent(
|
||||
)
|
||||
```
|
||||
|
||||
**Todo Tools** (`apps/agent/src/todos.py`):
|
||||
**Todo Tools** (`agent/src/todos.py`):
|
||||
|
||||
```python
|
||||
@tool
|
||||
@@ -161,7 +163,7 @@ def get_todos(runtime: ToolRuntime):
|
||||
|
||||
### Frontend
|
||||
|
||||
**Canvas Component** (`apps/app/src/components/canvas/index.tsx`):
|
||||
**Canvas Component** (`src/components/canvas/index.tsx`):
|
||||
|
||||
```typescript
|
||||
export function Canvas() {
|
||||
@@ -182,7 +184,7 @@ export function Canvas() {
|
||||
}
|
||||
```
|
||||
|
||||
**Todo List** (`apps/app/src/components/canvas/todo-list.tsx`):
|
||||
**Todo List** (`src/components/canvas/todo-list.tsx`):
|
||||
|
||||
```typescript
|
||||
export function TodoList({ todos, onUpdate, isAgentRunning }: TodoListProps) {
|
||||
@@ -225,37 +227,32 @@ export function TodoList({ todos, onUpdate, isAgentRunning }: TodoListProps) {
|
||||
- **Frontend**: Next.js 16, React 19, TailwindCSS 4
|
||||
- **Agent**: LangGraph (Python), OpenAI GPT-5.2
|
||||
- **CopilotKit**: React hooks for agent integration (v2)
|
||||
- **Monorepo**: Turborepo with pnpm workspaces
|
||||
- **Other**: MCP (Model Context Protocol) integration, Recharts for generative UI examples
|
||||
- **Build**: npm with concurrently for parallel dev processes
|
||||
- **Other**: Recharts for generative UI examples
|
||||
|
||||
## Development
|
||||
|
||||
This is a Turborepo monorepo using pnpm workspaces.
|
||||
|
||||
```bash
|
||||
# Install dependencies (all apps)
|
||||
pnpm install
|
||||
# Install dependencies (also sets up agent via postinstall)
|
||||
npm install
|
||||
|
||||
# Start all apps (app, agent, mcp)
|
||||
pnpm dev
|
||||
# Start both frontend and agent
|
||||
npm run dev
|
||||
|
||||
# Start individually
|
||||
pnpm dev:app # Next.js frontend on port 3000
|
||||
pnpm dev:agent # LangGraph agent on port 8123
|
||||
pnpm dev:mcp # MCP server
|
||||
npm run dev:ui # Next.js frontend on port 3000
|
||||
npm run dev:agent # LangGraph agent on port 8123
|
||||
|
||||
# Build all apps
|
||||
pnpm build
|
||||
|
||||
# Lint all apps
|
||||
pnpm lint
|
||||
# Build
|
||||
npm run build
|
||||
```
|
||||
|
||||
### Environment Setup
|
||||
|
||||
```bash
|
||||
# Set OpenAI API key for the agent
|
||||
echo 'OPENAI_API_KEY=your-key-here' > apps/agent/.env
|
||||
# Set OpenAI API key
|
||||
cp .env.example .env
|
||||
# Edit .env and add your OPENAI_API_KEY
|
||||
```
|
||||
|
||||
## Design Principles
|
||||
@@ -265,18 +262,6 @@ echo 'OPENAI_API_KEY=your-key-here' > apps/agent/.env
|
||||
3. **Template-first** - Code is meant to be forked and extended
|
||||
4. **Showcasing agent-driven UI** - Demonstrates AI manipulating application state beyond chat
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
Possible extensions to demonstrate more CopilotKit capabilities:
|
||||
|
||||
- Todo categories/tags/priorities
|
||||
- Agent-driven task organization (auto-categorize, suggest priorities)
|
||||
- Due dates and reminders
|
||||
- Subtasks and dependencies
|
||||
- Export/import todo lists
|
||||
- Undo/redo with state history
|
||||
- Real-time collaboration
|
||||
|
||||
---
|
||||
|
||||
## Key Takeaways for Developers
|
||||
|
||||
@@ -2,26 +2,25 @@
|
||||
FROM node:20-slim AS frontend
|
||||
|
||||
WORKDIR /app
|
||||
RUN corepack enable
|
||||
|
||||
COPY package.json pnpm-workspace.yaml pnpm-lock.yaml* ./
|
||||
COPY apps/app/package.json ./apps/app/
|
||||
RUN pnpm install --no-frozen-lockfile
|
||||
COPY package.json ./
|
||||
RUN npm install --ignore-scripts
|
||||
|
||||
COPY apps/app/ ./apps/app/
|
||||
COPY src/ ./src/
|
||||
COPY public/ ./public/
|
||||
COPY next.config.ts tsconfig.json postcss.config.mjs ./
|
||||
COPY showcase.json ./showcase.json
|
||||
|
||||
# Docker override: use AG-UI HttpAgent instead of LangGraphAgent
|
||||
# (LangGraphAgent needs Docker-in-Docker which Railway doesn't provide)
|
||||
# Docker override: replace catch-all with HttpAgent route (LangGraphAgent needs Docker-in-Docker)
|
||||
# Next.js 16+ rejects both /api/copilotkit/route.ts AND /api/copilotkit/[[...slug]]/route.ts
|
||||
RUN rm -f ./apps/app/src/app/api/copilotkit/\[\[...slug\]\]/route.ts
|
||||
COPY docker-route-override.ts ./apps/app/src/app/api/copilotkit/route.ts
|
||||
RUN pnpm --filter @repo/app add @ag-ui/client
|
||||
RUN rm -f ./src/app/api/copilotkit/\[\[...slug\]\]/route.ts
|
||||
COPY docker-route-override.ts ./src/app/api/copilotkit/route.ts
|
||||
RUN npm install @ag-ui/client
|
||||
|
||||
ENV NODE_OPTIONS="--max-old-space-size=4096"
|
||||
# Next.js 16+ uses Turbopack by default; use --webpack for serverExternalPackages compat
|
||||
RUN pnpm --filter @repo/app exec next build --webpack
|
||||
RUN npx next build --webpack
|
||||
|
||||
# Stage 2: Production image with Python + Node
|
||||
FROM python:3.12.10-slim AS runner
|
||||
@@ -41,7 +40,7 @@ WORKDIR /app
|
||||
# Install Python deps — EXCLUDING langgraph-cli and langgraph-api
|
||||
# (they need Docker-in-Docker which Railway doesn't provide)
|
||||
# Instead serve via ag-ui-langgraph + copilotkit (same protocol, no Docker needed)
|
||||
COPY apps/agent/ ./apps/agent/
|
||||
COPY agent/ ./agent/
|
||||
# Install ag-ui-langgraph FIRST at pinned version (before copilotkit can override it)
|
||||
RUN uv pip install --system "ag-ui-langgraph[fastapi]==0.0.22" && \
|
||||
uv pip install --system --no-deps "copilotkit==0.1.78" && \
|
||||
@@ -61,9 +60,9 @@ RUN uv pip install --system "ag-ui-langgraph[fastapi]==0.0.22" && \
|
||||
COPY serve.py ./
|
||||
|
||||
# Copy Next.js standalone build
|
||||
COPY --from=frontend /app/apps/app/.next/standalone ./
|
||||
COPY --from=frontend /app/apps/app/.next/static ./apps/app/.next/static
|
||||
COPY --from=frontend /app/apps/app/public ./apps/app/public
|
||||
COPY --from=frontend /app/.next/standalone ./
|
||||
COPY --from=frontend /app/.next/static ./.next/static
|
||||
COPY --from=frontend /app/public ./public
|
||||
|
||||
COPY entrypoint.sh ./
|
||||
RUN chmod +x entrypoint.sh
|
||||
|
||||
@@ -8,33 +8,19 @@ https://github.com/user-attachments/assets/47761912-d46a-4fb3-b9bd-cb41ddd02e34
|
||||
|
||||
- Node.js 18+
|
||||
- Python 3.8+
|
||||
- Any of the following package managers:
|
||||
- [pnpm](https://pnpm.io/installation) (recommended)
|
||||
- npm
|
||||
- [yarn](https://classic.yarnpkg.com/lang/en/docs/install/#mac-stable)
|
||||
- [bun](https://bun.sh/)
|
||||
- [uv](https://docs.astral.sh/uv/) (Python package manager)
|
||||
- OpenAI API Key (for the LangGraph agent)
|
||||
|
||||
> **Note:** This repository ignores lock files (package-lock.json, yarn.lock, pnpm-lock.yaml, bun.lockb) to avoid conflicts between different package managers. Each developer should generate their own lock file using their preferred package manager. After that, make sure to delete it from the .gitignore.
|
||||
|
||||
## Getting Started
|
||||
|
||||
1. Install dependencies using your preferred package manager:
|
||||
1. Install dependencies:
|
||||
|
||||
```bash
|
||||
# Using pnpm (recommended)
|
||||
pnpm install
|
||||
|
||||
# Using npm
|
||||
npm install
|
||||
|
||||
# Using yarn
|
||||
yarn install
|
||||
|
||||
# Using bun
|
||||
bun install
|
||||
```
|
||||
|
||||
This will also install the Python agent dependencies via `uv sync`.
|
||||
|
||||
2. Set up your environment variables:
|
||||
|
||||
```bash
|
||||
@@ -50,34 +36,47 @@ OPENAI_API_KEY=your-openai-api-key-here
|
||||
3. Start the development server:
|
||||
|
||||
```bash
|
||||
# Using pnpm
|
||||
pnpm dev
|
||||
|
||||
# Using npm
|
||||
npm run dev
|
||||
|
||||
# Using yarn
|
||||
yarn dev
|
||||
|
||||
# Using bun
|
||||
bun run dev
|
||||
```
|
||||
|
||||
This will start both the UI and agent servers concurrently.
|
||||
|
||||
## Available Scripts
|
||||
|
||||
The following scripts can also be run using your preferred package manager:
|
||||
|
||||
- `dev` - Starts both UI and agent servers in development mode
|
||||
- `dev:debug` - Starts development servers with debug logging enabled
|
||||
- `dev:ui` - Starts only the Next.js UI server
|
||||
- `dev:agent` - Starts only the LangGraph agent server
|
||||
- `build` - Builds the Next.js application for production
|
||||
- `start` - Starts the production server
|
||||
- `lint` - Runs ESLint for code linting
|
||||
- `install:agent` - Installs Python dependencies for the agent
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
├── src/ # Next.js frontend source
|
||||
│ ├── app/
|
||||
│ │ ├── page.tsx # Main page
|
||||
│ │ └── api/copilotkit/ # CopilotKit API route
|
||||
│ ├── components/
|
||||
│ │ ├── example-canvas/ # Todo list UI
|
||||
│ │ ├── example-layout/ # Layout: chat + canvas side-by-side
|
||||
│ │ └── generative-ui/ # Example generative UI components
|
||||
│ └── hooks/
|
||||
├── agent/ # LangGraph Python agent
|
||||
│ ├── main.py # Agent entry point
|
||||
│ └── src/
|
||||
│ ├── todos.py # Todo tools and state schema
|
||||
│ └── query.py # Example data query tool
|
||||
├── scripts/ # Agent setup and run scripts
|
||||
│ ├── setup-agent.sh / .bat
|
||||
│ └── run-agent.sh / .bat
|
||||
├── public/ # Static assets
|
||||
├── next.config.ts
|
||||
├── tsconfig.json
|
||||
└── package.json
|
||||
```
|
||||
|
||||
## A2UI — Agent-to-User Interface
|
||||
|
||||
This starter includes [A2UI](https://a2ui.org/specification/) support, allowing the agent to generate rich, interactive UI surfaces declaratively. Instead of returning plain text, the agent sends a JSON description of the UI it wants to render, and the frontend turns it into real components.
|
||||
@@ -101,15 +100,15 @@ Both patterns use the same catalog on the frontend — the difference is where t
|
||||
|
||||
### Key files
|
||||
|
||||
| Purpose | Path |
|
||||
| ------------------------------------ | ----------------------------------------------------------- |
|
||||
| Catalog definitions (Zod schemas) | `apps/app/src/app/declarative-generative-ui/definitions.ts` |
|
||||
| Catalog renderers (React components) | `apps/app/src/app/declarative-generative-ui/renderers.tsx` |
|
||||
| Catalog registration | `apps/app/src/app/layout.tsx` |
|
||||
| Fixed-schema agent tool | `apps/agent/src/a2ui_fixed_schema.py` |
|
||||
| Dynamic-schema agent tool | `apps/agent/src/a2ui_dynamic_schema.py` |
|
||||
| Flight schema JSON | `apps/agent/src/a2ui/schemas/flight_schema.json` |
|
||||
| Showcase config | `showcase.json` |
|
||||
| Purpose | Path |
|
||||
| ------------------------------------ | -------------------------------------------------- |
|
||||
| Catalog definitions (Zod schemas) | `src/app/declarative-generative-ui/definitions.ts` |
|
||||
| Catalog renderers (React components) | `src/app/declarative-generative-ui/renderers.tsx` |
|
||||
| Catalog registration | `src/app/layout.tsx` |
|
||||
| Fixed-schema agent tool | `agent/src/a2ui_fixed_schema.py` |
|
||||
| Dynamic-schema agent tool | `agent/src/a2ui_dynamic_schema.py` |
|
||||
| Flight schema JSON | `agent/src/a2ui/schemas/flight_schema.json` |
|
||||
| Showcase config | `showcase.json` |
|
||||
|
||||
### Adding a custom component
|
||||
|
||||
@@ -136,7 +135,7 @@ Both patterns use the same catalog on the frontend — the difference is where t
|
||||
|
||||
### Adding a new fixed-schema tool
|
||||
|
||||
1. Create a JSON schema file in `apps/agent/src/a2ui/schemas/` describing the component tree.
|
||||
1. Create a JSON schema file in `agent/src/a2ui/schemas/` describing the component tree.
|
||||
2. Create a Python tool that loads the schema with `a2ui.load_schema()` and returns `a2ui.render(operations=[...])` with your data. See `a2ui_fixed_schema.py` for the pattern.
|
||||
|
||||
### Showcase mode
|
||||
@@ -167,7 +166,7 @@ This project is licensed under the MIT License - see the LICENSE file for detail
|
||||
|
||||
If you see "I'm having trouble connecting to my tools", make sure:
|
||||
|
||||
1. The LangGraph agent is running on port 8000
|
||||
1. The LangGraph agent is running on port 8123
|
||||
2. Your OpenAI API key is set correctly
|
||||
3. Both servers started successfully
|
||||
|
||||
@@ -176,5 +175,5 @@ If you see "I'm having trouble connecting to my tools", make sure:
|
||||
If you encounter Python import errors:
|
||||
|
||||
```bash
|
||||
npm install:agent
|
||||
npm run install:agent
|
||||
```
|
||||
|
||||
@@ -6,5 +6,5 @@
|
||||
"graphs": {
|
||||
"sample_agent": "./main.py:graph"
|
||||
},
|
||||
"env": "../../.env"
|
||||
"env": "../.env"
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"name": "@repo/agent",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "npx @langchain/langgraph-cli dev --port 8123 --no-browser",
|
||||
"postinstall": "uv sync"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@langchain/langgraph-cli": "^1.1.12"
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
{
|
||||
"name": "@repo/app",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev --turbopack",
|
||||
"build": "next build",
|
||||
"start": "next start"
|
||||
},
|
||||
"dependencies": {
|
||||
"@copilotkit/a2ui-renderer": "https://pkg.pr.new/CopilotKit/CopilotKit/@copilotkit/a2ui-renderer@cfeb1c68c43e1c0fc00bcef91ea48b065668218b",
|
||||
"@copilotkit/react-core": "https://pkg.pr.new/CopilotKit/CopilotKit/@copilotkit/react-core@cfeb1c68c43e1c0fc00bcef91ea48b065668218b",
|
||||
"@copilotkit/react-ui": "https://pkg.pr.new/CopilotKit/CopilotKit/@copilotkit/react-ui@cfeb1c68c43e1c0fc00bcef91ea48b065668218b",
|
||||
"@copilotkit/runtime": "https://pkg.pr.new/CopilotKit/CopilotKit/@copilotkit/runtime@cfeb1c68c43e1c0fc00bcef91ea48b065668218b",
|
||||
"@copilotkit/shared": "https://pkg.pr.new/CopilotKit/CopilotKit/@copilotkit/shared@cfeb1c68c43e1c0fc00bcef91ea48b065668218b",
|
||||
"@radix-ui/react-checkbox": "^1.3.3",
|
||||
"@radix-ui/react-label": "^2.1.8",
|
||||
"@radix-ui/react-separator": "^1.1.8",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"hono": "^4.12.10",
|
||||
"lucide-react": "^0.577.0",
|
||||
"next": "16.1.6",
|
||||
"react": "^19.2.4",
|
||||
"react-dom": "^19.2.4",
|
||||
"react-rnd": "^10.5.2",
|
||||
"react18-json-view": "^0.2.9",
|
||||
"recharts": "^3.7.0",
|
||||
"tailwind-merge": "^3.5.0",
|
||||
"zod": "^3.23.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/postcss": "^4",
|
||||
"@types/node": "^20",
|
||||
"@types/react": "^19",
|
||||
"@types/react-dom": "^19",
|
||||
"tailwindcss": "^4",
|
||||
"typescript": "^5"
|
||||
}
|
||||
}
|
||||
@@ -10,8 +10,8 @@ services:
|
||||
|
||||
agent:
|
||||
build:
|
||||
context: ./apps/agent
|
||||
dockerfile: ../../docker/Dockerfile.agent
|
||||
context: ./agent
|
||||
dockerfile: ../docker/Dockerfile.agent
|
||||
environment:
|
||||
- OPENAI_API_KEY=test-key-for-aimock
|
||||
- OPENAI_BASE_URL=http://aimock:4010/v1
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Dockerfile for the Python LangGraph agent.
|
||||
# Mirrors the user experience: uv sync + langgraph dev (same as pnpm dev:agent).
|
||||
# Mirrors the user experience: uv sync + langgraph dev (same as npm run dev:agent).
|
||||
FROM python:3.12-slim
|
||||
|
||||
RUN apt-get update && \
|
||||
|
||||
@@ -7,16 +7,11 @@ RUN apk add --no-cache libc6-compat
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Install pnpm
|
||||
RUN corepack enable && corepack prepare pnpm@latest --activate
|
||||
|
||||
# Copy package files
|
||||
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml .pnpmfile.cjs ./
|
||||
COPY apps/app/package.json ./apps/app/
|
||||
COPY turbo.json ./
|
||||
COPY package.json ./
|
||||
|
||||
# Install dependencies
|
||||
RUN pnpm install --frozen-lockfile
|
||||
RUN npm install --ignore-scripts
|
||||
|
||||
# Build the application
|
||||
FROM base AS builder
|
||||
@@ -24,16 +19,12 @@ WORKDIR /app
|
||||
|
||||
# Copy dependencies from deps stage
|
||||
COPY --from=deps /app/node_modules ./node_modules
|
||||
COPY --from=deps /app/apps/app/node_modules ./apps/app/node_modules
|
||||
|
||||
# Copy source code
|
||||
COPY . .
|
||||
|
||||
# Enable pnpm
|
||||
RUN corepack enable && corepack prepare pnpm@latest --activate
|
||||
|
||||
# Build the Next.js app
|
||||
RUN pnpm --filter @repo/app build
|
||||
RUN npx next build
|
||||
|
||||
# Production image
|
||||
FROM base AS runner
|
||||
@@ -45,9 +36,9 @@ RUN addgroup --system --gid 1001 nodejs
|
||||
RUN adduser --system --uid 1001 nextjs
|
||||
|
||||
# Copy built application
|
||||
COPY --from=builder /app/apps/app/public ./apps/app/public
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/apps/app/.next/standalone ./
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/apps/app/.next/static ./apps/app/.next/static
|
||||
COPY --from=builder /app/public ./public
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
|
||||
|
||||
USER nextjs
|
||||
|
||||
@@ -56,4 +47,4 @@ EXPOSE 3000
|
||||
ENV PORT=3000
|
||||
ENV HOSTNAME="0.0.0.0"
|
||||
|
||||
CMD ["node", "apps/app/server.js"]
|
||||
CMD ["node", "server.js"]
|
||||
|
||||
@@ -18,7 +18,7 @@ sleep 3
|
||||
|
||||
# Start Next.js standalone
|
||||
echo "[entrypoint] Starting Next.js on port ${PORT:-3000}..."
|
||||
HOSTNAME=0.0.0.0 PORT=${PORT:-3000} node apps/app/server.js 2>&1 &
|
||||
HOSTNAME=0.0.0.0 PORT=${PORT:-3000} node server.js 2>&1 &
|
||||
NEXT_PID=$!
|
||||
|
||||
echo "[entrypoint] Agent=$AGENT_PID Next=$NEXT_PID"
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
{
|
||||
"match": {},
|
||||
"response": {
|
||||
"content": "You're currently running against aimock (a mock LLM server). This response is a catch-all for requests that don't match any test fixture. To use a real LLM: (1) Add your OPENAI_API_KEY to .env, (2) Remove or unset OPENAI_BASE_URL from your environment so requests go to OpenAI instead of aimock, (3) Restart with `pnpm dev`."
|
||||
"content": "You're currently running against aimock (a mock LLM server). This response is a catch-all for requests that don't match any test fixture. To use a real LLM: (1) Add your OPENAI_API_KEY to .env, (2) Remove or unset OPENAI_BASE_URL from your environment so requests go to OpenAI instead of aimock, (3) Restart with `npm run dev`."
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -1,24 +1,46 @@
|
||||
{
|
||||
"name": "copilotkit-langgraph-template",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "turbo run dev",
|
||||
"dev:app": "turbo run dev --filter='@repo/app'",
|
||||
"dev:agent": "turbo run dev --filter='@repo/agent'",
|
||||
"dev:mcp": "turbo run dev --filter='@repo/mcp'",
|
||||
"build": "turbo run build",
|
||||
"lint": "turbo run lint",
|
||||
"clean": "turbo run clean",
|
||||
"local-install": "bash -c 'cd ../../.. && ./node_modules/.bin/nx run-many -t build -p @copilotkit/react-core @copilotkit/react-ui @copilotkit/runtime @copilotkitnext/shared' && bash -c 'cd ../../../.. && cd ag-ui && npx -y pnpm@10 install && npx -y pnpm@10 run build' && COPILOTKIT_LOCAL=1 pnpm install && bash -c 'SRC=../../../../ag-ui/middlewares/a2ui-middleware/dist; for f in $(find ../../.. -path \"*/@ag-ui/a2ui-middleware/dist/index.js\" 2>/dev/null); do DIR=$(dirname \"$f\"); cp $SRC/index.js $SRC/index.mjs $SRC/index.d.ts $SRC/index.d.mts \"$DIR/\" 2>/dev/null; done; echo \"a2ui-middleware: all copies patched with local build\"'"
|
||||
"dev": "concurrently \"npm run dev:ui\" \"npm run dev:agent\" --names ui,agent --prefix-colors blue,green --kill-others",
|
||||
"dev:debug": "LOG_LEVEL=debug npm run dev",
|
||||
"dev:ui": "next dev --turbopack",
|
||||
"dev:agent": "./scripts/run-agent.sh || scripts/run-agent.bat",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"install:agent": "./scripts/setup-agent.sh || scripts\\setup-agent.bat",
|
||||
"postinstall": "npm run install:agent"
|
||||
},
|
||||
"dependencies": {
|
||||
"@copilotkit/a2ui-renderer": "https://pkg.pr.new/CopilotKit/CopilotKit/@copilotkit/a2ui-renderer@cfeb1c68c43e1c0fc00bcef91ea48b065668218b",
|
||||
"@copilotkit/react-core": "https://pkg.pr.new/CopilotKit/CopilotKit/@copilotkit/react-core@cfeb1c68c43e1c0fc00bcef91ea48b065668218b",
|
||||
"@copilotkit/react-ui": "https://pkg.pr.new/CopilotKit/CopilotKit/@copilotkit/react-ui@cfeb1c68c43e1c0fc00bcef91ea48b065668218b",
|
||||
"@copilotkit/runtime": "https://pkg.pr.new/CopilotKit/CopilotKit/@copilotkit/runtime@cfeb1c68c43e1c0fc00bcef91ea48b065668218b",
|
||||
"@copilotkit/shared": "https://pkg.pr.new/CopilotKit/CopilotKit/@copilotkit/shared@cfeb1c68c43e1c0fc00bcef91ea48b065668218b",
|
||||
"@radix-ui/react-checkbox": "^1.3.3",
|
||||
"@radix-ui/react-label": "^2.1.8",
|
||||
"@radix-ui/react-separator": "^1.1.8",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"hono": "^4.12.10",
|
||||
"lucide-react": "^0.577.0",
|
||||
"next": "16.1.6",
|
||||
"react": "^19.2.4",
|
||||
"react-dom": "^19.2.4",
|
||||
"react-rnd": "^10.5.2",
|
||||
"react18-json-view": "^0.2.9",
|
||||
"recharts": "^3.7.0",
|
||||
"tailwind-merge": "^3.5.0",
|
||||
"zod": "^3.23.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/postcss": "^4",
|
||||
"@types/node": "^20",
|
||||
"@types/react": "^19",
|
||||
"@types/react-dom": "^19",
|
||||
"concurrently": "^9.1.2",
|
||||
"turbo": "^2.5.4"
|
||||
},
|
||||
"packageManager": "pnpm@9.0.0",
|
||||
"pnpm": {
|
||||
"overrides": {
|
||||
"esbuild": "^0.27.3"
|
||||
}
|
||||
"tailwindcss": "^4",
|
||||
"typescript": "^5"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
packages:
|
||||
- "apps/app"
|
||||
- "apps/agent"
|
||||
|
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 391 B After Width: | Height: | Size: 391 B |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 128 B After Width: | Height: | Size: 128 B |
|
Before Width: | Height: | Size: 385 B After Width: | Height: | Size: 385 B |
@@ -0,0 +1,3 @@
|
||||
@echo off
|
||||
cd /d "%~dp0..\agent"
|
||||
npx @langchain/langgraph-cli dev --port 8123 --no-browser
|
||||
@@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
cd "$(dirname "$0")/../agent" || exit 1
|
||||
npx @langchain/langgraph-cli dev --port 8123 --no-browser
|
||||
@@ -0,0 +1,3 @@
|
||||
@echo off
|
||||
cd /d "%~dp0..\agent"
|
||||
uv sync
|
||||
@@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
cd "$(dirname "$0")/../agent" || exit 1
|
||||
uv sync
|
||||
@@ -7,7 +7,7 @@ import os
|
||||
import sys
|
||||
|
||||
# Add the agent directory to the path so imports work
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "apps", "agent"))
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "agent"))
|
||||
|
||||
import uvicorn
|
||||
from fastapi import FastAPI
|
||||
|
||||
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |