Gourmet AI - Shared State Recipe Copilot

July 13, 2026 ยท View on GitHub

Gourmet AI is a state-of-the-art Recipe Assistant demonstrating real-time, bidirectional state synchronization between an AI Agent and a React/Next.js frontend using CopilotKit and Pydantic AI.


๐Ÿš€ Key Features

1. Dual-Theme Engine (Light & Dark Modes)

  • Responsive Theme Context: Detects local settings (localStorage) or falls back to system OS preferences (prefers-color-scheme).
  • Cohesive Sidebar Variables: Automatically shifts the ChatGPT-style sidebar from a creamy off-white (#f5f4f0) in Light Mode to a premium stone charcoal (#0d0d0e) in Dark Mode.
  • Component-Wide Transitions: Main panel card, header bar, and the CopilotKit chat interface transition seamlessly.

2. Drag-to-Resize Sidebars (Adjustable Widths)

  • Custom Resizable Hooks: Supports dynamic mouse coordinate tracking for dragging and resizing boundaries.
  • Left Navigation Sidebar: Draggable right border (limits: 200px to 450px).
  • Right Assistant Sidebar: Draggable left border (limits: 280px to 550px).
  • Smooth Grabbing UX: Blocks text selection (user-select: none) and changes body-cursor properties while dragging to prevent coordinate cursor flickering.

3. Mobile & Tablet Responsiveness

  • Sticky Header: Pins the header (hamburger menu trigger, brand tags, and connection badges) to the top of the viewport (sticky top-0 z-30). The main workspace panel scroll is isolated to allow the header to float correctly at any scroll depth.
  • Slide-over Navigation Drawer: Hides the desktop left sidebar inline and shows a Hamburger icon. Triggering it slides the navigation panel in as an overlay drawer, complete with a backdrop overlay mask.
  • Bottom Chat Assistant Sheet: Collapses the right desktop sidebar panel into a pull-up overlay sheet with a grab handle bar.

4. MCP Dashboard & SSE Streaming Console

  • SSE MCP Dashboard: Houses an interactive Server-Sent Events MCP console to review tool executions and raw logs side-by-side with the recipe editor.
  • Mock Fallback Route: Simulates full AG-UI SSE protocol streams (TEXT_MESSAGE_START, TEXT_MESSAGE_CONTENT, TEXT_MESSAGE_END, TOOL_CALL_START, TOOL_CALL_ARGS, TOOL_CALL_END, RUN_FINISHED) enabling mock development without API key authorization errors.

๐Ÿ› ๏ธ Technology Stack

  • Frontend Framework: Next.js (App Router, Tailwind CSS, TypeScript).
  • AI Integration: @copilotkit/react-core/v2 (CopilotChat, CopilotKit, EmptyAdapter).
  • Backend Reference: Python FastAPI, Pydantic AI, Model Context Protocol (MCP).
  • Icons: Lucide React.

๐Ÿ“‚ Project Architecture

โ”œโ”€โ”€ src/
โ”‚   โ”œโ”€โ”€ app/
โ”‚   โ”‚   โ”œโ”€โ”€ api/
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ copilotkit/
โ”‚   โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ [...path]/route.ts # Next.js API route handling CopilotKit & Mock SSE
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ mcp/
โ”‚   โ”‚   โ”‚       โ””โ”€โ”€ route.ts           # SSE-compliant MCP log streamer
โ”‚   โ”‚   โ”œโ”€โ”€ globals.css                # Adaptive theme tokens, responsive overrides & resizer variables
โ”‚   โ”‚   โ”œโ”€โ”€ layout.tsx                 # Root layout styling injection
โ”‚   โ”‚   โ””โ”€โ”€ page.tsx                   # Main layout grid, drawers, and resizing listeners
โ”‚   โ”œโ”€โ”€ components/
โ”‚   โ”‚   โ”œโ”€โ”€ chat-sidebar.tsx           # Custom resizable Right Chat Sidebar panel
โ”‚   โ”‚   โ”œโ”€โ”€ mcp-dashboard.tsx          # Real-time SSE logs reviewer dashboard
โ”‚   โ”‚   โ”œโ”€โ”€ nav-sidebar.tsx            # Left ChatGPT-style adaptive side-navigation panel
โ”‚   โ”‚   โ”œโ”€โ”€ providers.tsx              # Groups CopilotKit, Recipe, and Theme providers
โ”‚   โ”‚   โ””โ”€โ”€ recipe/                    # Recipe editor card forms and lists components
โ”‚   โ”œโ”€โ”€ contexts/
โ”‚   โ”‚   โ”œโ”€โ”€ recipe-context.tsx         # recipe state synchronization logic
โ”‚   โ”‚   โ””โ”€โ”€ theme-context.tsx          # client theme preference state manager
โ”‚   โ”œโ”€โ”€ utils/
โ”‚   โ”‚   โ”œโ”€โ”€ use-mobile-chat.ts         # Touch height drag helper for mobile bottom sheets
โ”‚   โ”‚   โ”œโ”€โ”€ use-mobile-view.ts         # Breakpoint listener (< 1024px) for tablet/mobile layout shifts
โ”‚   โ”‚   โ””โ”€โ”€ use-resizable.ts           # Mouse grab coordinate hook for adjustable widths
โ””โ”€โ”€ backend/                           # Python reference setup
    โ”œโ”€โ”€ main.py                        # Pydantic AI agent backend mounting to CopilotKit
    โ”œโ”€โ”€ requirements.txt               # Backend dependencies
    โ””โ”€โ”€ README.md                      # Backend run instructions

๐Ÿš€ Getting Started

1. Frontend Setup

First, install dependencies:

npm install

Start the local development server:

npm run dev

Open http://localhost:3000 in your browser to view the application.

2. Python Backend Setup (Reference)

Navigate to the backend directory:

cd backend

Create a virtual environment and install requirements:

python -m venv venv
venv\Scripts\activate # On Windows
pip install -r requirements.txt

Set up your environment variables (e.g. OpenAI / Anthropic keys) and run the FastAPI server:

uvicorn main:app --reload --port 8000

The frontend automatically references this backend runtime endpoint when not in mock mode.


๐Ÿง  How the Tech Stack Works in This Project

The Big Picture (For Everyone)

Imagine you're ordering a custom pizza through an app:

  • You type what you want: "Make it spicy"
  • A waiter takes your order and translates it to the kitchen.
  • The kitchen (AI brain) figures out what to cook.
  • Results stream back to you in real-time โ€” you see the pizza being built piece by piece.
  • A menu board on the wall updates live showing your new pizza.

That's exactly what this app does โ€” but for recipes. Each technology plays a specific role in that pipeline.


1. ๐Ÿค– AG-UI (Agent UI Protocol)

For Regular Folks:

Think of AG-UI as a universal language that AI agents and user interfaces agree to speak. Just like USB-C is a universal plug that works for phones, laptops, and headphones, AG-UI is a universal "plug" standard so any AI agent can talk to any frontend. Without it, every AI company would speak a different language and nothing would work together.

For Developers:

AG-UI is an open-source, event-based streaming protocol that standardizes how AI agents communicate with UIs. It defines a set of typed events that agents emit over SSE:

RUN_STARTED          โ†’ agent begins processing
TEXT_MESSAGE_START   โ†’ assistant starts typing  
TEXT_MESSAGE_CONTENT โ†’ streaming text delta chunks
TEXT_MESSAGE_END     โ†’ message complete
TOOL_CALL_START      โ†’ agent calling a tool (e.g. display_recipe)
TOOL_CALL_ARGS       โ†’ tool arguments streamed as JSON chunks
TOOL_CALL_END        โ†’ tool call complete
RUN_FINISHED         โ†’ agent run complete
STATE_SNAPSHOT       โ†’ shared state update (recipe card data)

In this project, the mock backend (our API route handler in route.ts) produces these exact AG-UI events, and LangGraphHttpAgent parses them to drive the CopilotKit UI.

Key file: route.ts โ€” the mock backend that streams AG-UI events.


2. ๐ŸŽฎ CopilotKit

For Regular Folks:

CopilotKit is like a ready-made AI chat widget in a box. Instead of building a chat bubble, a typing indicator, a sidebar, and connecting it all to an AI, CopilotKit gives you all of that pre-built. You just drop it into your app and configure it. It's like installing a fancy intercom system โ€” you don't wire the whole building, you just plug in the box.

For Developers:

CopilotKit operates in two environments:

  • Frontend (React):

    <CopilotKit runtimeUrl="/api/copilotkit/pydantic-ai" agent="shared_state">
      <CopilotSidebar /> // The chat panel
    </CopilotKit>
    
    • Provides hooks like useAgent() and useCopilotKit().
    • Manages agent state, message threads, and tool-call rendering.
    • Handles the WebSocket/SSE connection lifecycle.
  • Backend (Next.js API Route):

    const runtime = new CopilotRuntime({
      agents: {
        shared_state: new LangGraphHttpAgent({ url: "http://localhost:8000/copilotkit" })
      }
    });
    
    • CopilotRuntime acts as a secure middleware proxy between the browser and your AI agent.
    • Uses EmptyAdapter when the agent handles its own LLM API authorization calls.
    • Exposes /info (agent discovery) and GQL streaming endpoints.

Key files:

  • providers.tsx โ€” wraps the app with <CopilotKit> and contexts.
  • page.tsx โ€” implements sidebars, layouts, and workspace controls.
  • route.ts โ€” hosts the CopilotRuntime middleware backend.

3. ๐Ÿ Pydantic AI

For Regular Folks:

Pydantic AI is the actual brain of the operation โ€” a Python AI framework. When the real backend is running, it's where the AI model lives, thinks, and makes decisions. It's like the chef in the kitchen vs. the waiter (CopilotKit) vs. the menu display (your browser). It also keeps a shared notepad (called "state") that both the AI and your UI can read and update, so when the AI decides to change the recipe, your screen updates automatically.

For Developers:

Pydantic AI wraps LLMs with type-safe Python data models (Pydantic schemas) and exposes them via an AG-UI-compatible HTTP endpoint:

# backend/main.py
agent = Agent(
    model="openai:gpt-4o",
    deps_type=StateDeps,
    result_type=RecipeSnapshot,
)

@agent.tool
async def display_recipe(ctx: RunContext[StateDeps], recipe: RecipeSnapshot) -> str:
    ctx.deps.snapshot = recipe  # updates shared state snapshot
    return "Recipe updated"

app = agent.to_ag_ui(deps=StateDeps(RecipeSnapshot()))

The .to_ag_ui() call is the magic โ€” it converts the Pydantic AI agent into a FastAPI app that speaks the AG-UI protocol natively.

Key file: main.py (runs at http://localhost:8000).


4. ๐Ÿ”Œ MCP โ€” Model Context Protocol

For Regular Folks:

MCP is like giving the AI a USB drive full of tools. Instead of the AI only being able to chat, MCP lets it connect to external tools โ€” like searching the web, reading files, or calling third-party APIs. In this app, there's a built-in MCP Console (the dashboard panel at the bottom). You can click "Click to see MCP console" to see it live. It's like peeking into the AI's tool drawer and watching it select tools.

For Developers:

MCP (Model Context Protocol by Anthropic) is a standard for connecting AI models to external tool servers. Each MCP server exposes a list of tools the AI can call. In this project:

  • The MCP Console panel streams logs via SSE from /api/mcp/logs.
  • The console is toggled in the UI via the showMcp state.
  • CopilotKit's CopilotRuntime supports connecting to real MCP servers using an mcp action.
const runtime = new CopilotRuntime({
  actions: [{ type: "mcp", url: "http://localhost:3001/mcp" }]
});

Key file: route.ts โ€” MCP log streaming endpoint.


5. ๐Ÿ“ก SSE โ€” Server-Sent Events

For Regular Folks:

SSE is how the AI types in real-time in front of you instead of making you wait for the whole answer. Imagine calling a restaurant and they make you wait on hold until the chef finishes the whole dish vs. the chef narrating what they're doing step by step. SSE is the narrating version โ€” words appear one by one as the AI generates them. It's a one-way live radio signal from the server to your browser.

For Developers:

SSE (Server-Sent Events) is an HTTP-based streaming mechanism โ€” the server sends text/event-stream content type and keeps the connection open:

HTTP/1.1 200 OK
Content-Type: text/event-stream

data: {"type":"TEXT_MESSAGE_START","messageId":"msg-abc","role":"assistant"}
data: {"type":"TEXT_MESSAGE_CONTENT","messageId":"msg-abc","delta":"Here "}
data: {"type":"TEXT_MESSAGE_CONTENT","messageId":"msg-abc","delta":"is your "}
data: {"type":"RUN_FINISHED","runId":"run-xyz","outcome":"success"}

In this project, SSE is used in two places:

  1. Agent responses โ€” LangGraphHttpAgent in @ag-ui/client calls transformHttpEventStream() which reads the SSE body as a ReadableStream and parses each data: line as an AG-UI event object.
  2. MCP Console logs โ€” /api/mcp/logs streams terminal-style log lines as SSE so the console panel updates in real-time.

The browser-side parsing uses fetch() + getReader() on the response body (no WebSocket needed).


๐Ÿ—บ๏ธ How They All Connect โ€” The Full Journey

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  YOUR BROWSER (Next.js Frontend)                            โ”‚
โ”‚                                                             โ”‚
โ”‚  You type: "make it spicy"                                  โ”‚
โ”‚       โ†“                                                     โ”‚
โ”‚  <CopilotChat> (Inside ChatSidebar)                         โ”‚
โ”‚       โ†“                                                     โ”‚
โ”‚  useAgent("shared_state") โ†’ POST /api/copilotkit/pydantic-aiโ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
         โ†“  HTTP POST (GraphQL Handshake)
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  NEXT.JS API ROUTE (Middleware Runtime)                     โ”‚
โ”‚                                                             โ”‚
โ”‚  CopilotRuntime receives the GQL request                    โ”‚
โ”‚  Finds agent "shared_state" โ†’ LangGraphHttpAgent            โ”‚
โ”‚       โ†“                                                     โ”‚
โ”‚  fetch("http://localhost:8000/copilotkit")                  โ”‚
โ”‚  (Or calls mock simulator route when keyless)               โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
         โ†“  POST RunAgentInput JSON
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  PYDANTIC AI AGENT (Python FastAPI Backend)                 โ”‚
โ”‚                                                             โ”‚
โ”‚  Agent processes: "make it spicy"                           โ”‚
โ”‚  Calls tool: display_recipe({title:"Sichuan Peanut..."})    โ”‚
โ”‚       โ†“                                                     โ”‚
โ”‚  Streams back AG-UI events via SSE                          โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
         โ†‘  SSE stream of AG-UI events flows back up
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  COPILOTKIT RUNTIME parses events โ†’ GQL streaming response  โ”‚
โ”‚  โ†’ Browser receives real-time updates                       โ”‚
โ”‚  โ†’ Recipe card animates to "Sichuan Peanut Chili Noodles"   โ”‚
โ”‚  โ†’ MCP Console logs each step (via separate SSE channel)    โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

๐Ÿ“‹ Quick Reference Card

TechnologyRoleAnalogy
AG-UIStandard language for AIโ†”UIUSB-C universal plug
CopilotKitPre-built chat UI + backend proxyIntercom system in a box
Pydantic AIThe actual AI brain (Python)The chef in the kitchen
MCPPlugin system for AI toolsUSB drive full of tools
SSEReal-time streaming from serverLive radio broadcast