Introducing the Channels SDK New: Channels SDK · Bring your agent into Slack and Teams Talk to an Engineer Start building Slack & Teams Webinar · Aug 6 Webinar · Aug 6 Save your spot Back Here's How To Build Fullstack Agent Apps (Gemini, CopilotKit & LangGraph) By Anmol Baranwal and Nathan Tarbert September 23, 2025 AI agents are getting close to real world applications, but most developers still find it complex to build one. So we are going to build two practical agents: Post Generator that drafts LinkedIn/X content using live web search & Stack Analyzer that inspects GitHub repos and creates structured reports. We will be using Next.js frontend, FastAPI backend, CopilotKit , LangGraph workflows, and Google Gemini . You will find architecture, concepts, prompts, and practical stuff. Let's build it. Check out the CopilotKit GitHub ⭐️ 1. What are we building? We are building two practical agents using a full-stack setup: ✅ Post Generator Agent : creates LinkedIn/X posts grounded in live Google Search results. Here's a simplified call sequence of what will happen when a user generates a post. [User types prompt] ↓ Next.js UI ( CopilotChat ) ↓ ( POST /api/copilotkit → GraphQL) Next.js API route ( copilotkit ) ↓ ( forwards ) FastAPI backend (/copilotkit) ↓ ( LangGraph workflow) Post Generator graph nodes ↓ ( calls → Google Gemini + web search) Streaming responses & tool-logs ↓ Frontend UI renders chat + tool logs + final postcards ✅ Stack Analyzer Agent : analyzes a public GitHub repo (metadata, README, code manifests) and infers its stack. Here's a simplified call sequence of what will happen when a user analyzes the tech stack of a repo. [User pastes GitHub URL] ↓ Next.js UI (/stack-analyzer) ↓ /api/copilotkit → FastAPI ↓ Stack Analysis graph nodes ( gather_context → analyze → end) ↓ Streaming tool-logs & structured analysis cards Here's what we'll be building! 2. Tech Stack & Architecture At the core, we are going to use this stack for building these agents. Next.js 15 : frontend framework with TypeScript CopilotKit SDK : embed agents into UI ( @copilotkit/react-core , @copilotkit/runtime , @copilotkit/react-ui ) FastAPI & Uvicorn : backend framework for serving agents as APIs LangGraph (StateGraphs) : for building stateful agent workflows Google Gemini via google-genai (official SDK) : LLM for reasoning & text generation LangChain’s Google adapter : to plug Gemini into LangChain workflows Pydantic : for structured JSON tool outputs Here's the high-level architecture of the project. Project structure This is how our directory will look. The agent directory will hold the Python/FastAPI backend hosting the LangGraph agents, and the frontend directory hosts the Next.js 15 application, including UI routes, API routes, and shared components. . ├── assets/ ├── frontend/ ← Next.js 15 App (UI + API routes) │ ├── app/ │ │ ├── layout.tsx ← Wraps the app with <CopilotKit> │ │ ├── post-generator/ ← Post Generator UI routes │ │ ├── stack-analyzer/ ← Stack Analyzer UI routes │ │ └── api/ ← Next.js API routes used by the UI │ │ ... │ ├── contexts/LayoutContext.tsx │ ├── wrapper .tsx ← CopilotKit provider wrapper │ ├── components/ ← Shared UI components │ │ ... ├── agent/ ← FastAPI + LangGraph “agents” (Python) │ ├── main.py ← Registers agents and exposes them via FastAPI │ ├── posts_generator_agent.py ← Workflow for content creation agent │ ├── stack_agent.py ← Workflow for repo analysis agent │ ├── prompts.py ← Shared prompt templates │ ├── agent.py ← Core agent classes and helpers │ ... └── README.md ← Project overview and setup instructions Here's the GitHub repository and deployed live at copilot-kit-deepmind.vercel.app if you want to explore yourself. I will be covering the implementation with all the key concepts in the following sections. The easiest way to follow along is to clone the repo but I'm explaining how to build it from scratch. git clone https: //gi thub.com /CopilotKit/ CopilotKit-Deepmind.git cd copilotkit-deepmind Add necessary API Keys. Create a .env file under both the agent & frontend directory and add your Gemini API Key to the file. I've attached the docs link so it's easy to follow. The naming convention is the same for both directories. GOOGLE_API_KEY =<<your-gemini-key-here>> 3. Frontend Let's create the frontend. I'm attaching the project structure of the frontend again so it's easier for you to follow the whole layout. frontend/ ├── app/ │ ├── page.tsx ← landing redirect │ ├── post-generator/page.tsx← Post Generator UI │ ├── stack-analyzer/page.tsx← Stack Analyzer UI │ ├── api/ │ │ ├── copilotkit/route.ts← CopilotKit router endpoint │ │ └── chat/route.ts ← OpenAI research demo │ ├── contexts/LayoutContext.tsx │ ├── wrapper .tsx ← CopilotKit provider wrapper │ └── prompts/prompts.ts ← UI prompt templates ├── components/… ← shared UI components (tool-logs, cards, posts…) └── layout.tsx, globals.css, etc. If you don’t have a frontend, you can create a new Next.js app with TypeScript and then install the Copilotkit package. In the cloned repository, it’s already there, so you just need to install the dependencies using pnpm i under the frontend directory. // creates a nextjs app with typescript npx create-next-app@latest frontend Step 1: CopilotKit Provider & Layout Install the necessary CopilotKit packages. pnpm install copilotkit @copilotkit /react-core @copilotkit/ react-ui @copilotkit /runtime @copilotkit/ runtime -client-gql copilotkit is the lower-level SDK that bundles backend utilities for Python. Used here for wiring up state graphs, emitting state updates, and talking to Gemini. @copilotkit/react-core provides the core context and logic to connect your React app with the CopilotKit backend and MCP servers. @copilotkit/react-ui offers ready-made UI components like <CopilotChat /> to build AI chat or assistant interfaces quickly. @copilotkit/runtime is the server-side runtime library. Let's you declare agents, connect them to LangGraph workflows, and expose them through an API endpoint. @copilotkit/runtime-client-gql is a client for GraphQL transport. Used under the hood by the Next.js API route to proxy between the browser and your backend. The <CopilotKit> component must wrap the Copilot-aware parts of your application. In most cases, it's best to place it around the entire app, like in layout.tsx . The root layout wraps everything in a LayoutProvider and the CopilotKit client wrapper: import "./globals.css" import { LayoutProvider } from "./contexts/LayoutContext" import Wrapper from "./wrapper" export default function RootLayout({ children }) { return ( <html lang="en"> <LayoutProvider> < Wrapper > <body>{children}</body> </ Wrapper > </LayoutProvider> </html> ) } The LayoutProvider ( frontend\app\contexts\LayoutContext.tsx ) sets up a React context for layout state and picks the active agent based on the current route ( /post-generator or others) using usePathname() to detect the path. "use client" import { usePathname } from "next/navigation" import React, { createContext, useContext, useState } from "react" interface LayoutState { … } interface LayoutContextType { layoutState : LayoutState updateLayout : ( updates: Partial<LayoutState> ) => void } const LayoutContext = createContext<LayoutContextType | undefined >( undefined ) const defaultLayoutState = { agent : "post_generation_agent" , … } export function LayoutProvider ( { children } ) { const pathname = usePathname() const [layoutState, setLayoutState] = useState({ ...defaultLayoutState, agent : (pathname == "/post-generator" ? "post_generation_agent" : "stack_analysis_agent" ), }) const updateLayout = ( updates ) => setLayoutState( ( prev ) => ({ ...prev, ...updates })) return ( < LayoutContext.Provider value = {{ layoutState , updateLayout }}> {children} </ LayoutContext.Provider > ) } export function useLayout ( ) { return useContext(LayoutContext) } ... Here's the code for the CopilotKit client wrapper ( frontend\app\wrapper.tsx ). Every page is rendered inside so that UI components know which agent to call and where. "use client" import { CopilotKit } from "@copilotkit/react-core"; import { useLayout } from "./contexts/LayoutContext"; export default function Wrapper ({ children }: { children: React.ReactNode }) { const { layoutState } = useLayout() return ( <CopilotKit runtimeUrl="/api/copilotkit" agent={layoutState.agent}> {children} </CopilotKit> ) } Step 2: Next.js API Routes: Proxy to FastAPI CopilotKit Runtime endpoint available at Next.js API route app/api/copilotkit/route.ts just proxies all agent/graph calls to the FastAPI backend. Rather than calling the Python agent directly from the browser, we introduce a thin proxy. Why? Avoid CORS and cross‑origin issues Let Next.js handle authentication, environment‑specific routing, and bundling Uniform GraphQL/REST shape for the React UI (no Python payloads leak into client) In this example, we are only using a single agent, but if you are looking to run multiple LangGraph agents, check the official Multi-Agent guide . import { CopilotRuntime, copilotRuntimeNextJSAppRouterEndpoint, GoogleGenerativeAIAdapter } from "@copilotkit/runtime" ; import { NextRequest } from "next/server" ; // You can use any service adapter here for multi-agent support. const serviceAdapter = new GoogleGenerativeAIAdapter() ; const runtime = new CopilotRuntime({ remoteEndpoints : [{ url : process . env .NEXT_PUBLIC_LANGGRAPH_URL || "http://localhost:8000/copilotkit" }], }) ; export const POST = async ( req : N extRequest ) => { const { handleRequest } = copilot RuntimeNextJSAppRouterEndpoint({ runtime , serviceAdapter , endpoint : "/api/copilotkit" , }) ; return handle Request( req ) ; }; Here's a simple explanation of the above code: CopilotRuntime : the internal engine that connects your Copilot-enabled UI with agent endpoints. GoogleGenerativeAIAdapter : this adapter plugs in Google Gemini as the underlying LLM for agent workflows. remoteEndpoints : specifies where the agent logic lives (such as endpoint served by backend). copilotRuntimeNextJSAppRouterEndpoint : helper that wraps the incoming req and routes it to Copilot Runtime for agent processing. It returns a handleRequest method. Step 3: Auto‑Redirect to Post Generator One last thing is to redirect to /post-generator route whenever someone hits home / route at frontend\app\page.tsx . "use client" import "@copilotkit/react-ui/styles.css" ; import { useEffect } from "react" ; import { useRouter } from "next/navigation" ; import { useLayout } from "./contexts/LayoutContext" ; export default function GoogleDeepMindChatUI ( ) { const router = useRouter(); const { updateLayout } = useLayout(); useEffect( () => { updateLayout({ agent : "post_generation_agent" }); router.push( "/post-generator" ); }, [router]); return ( <> </> ) } Step 4: Post Generator Agent UI Let's create the frontend for Post Generator ( frontend/app/post-generator/page.tsx ) using the CopilotChat UI ( <CopilotChat> ), suggestions, and a custom action to render the final posts. The real codebase also includes UI extras like agent switching, quick actions and live tool logs. For clarity, I have trimmed them here, so check the code for full UI . import { CopilotChat, useCopilotChatSuggestions } from "@copilotkit/react-ui" import { initialPrompt, suggestionPrompt } from "../prompts/prompts" useCopilotChatSuggestions({ available: "enabled" , instructions: suggestionPrompt, }) return ( <div className = "…" > {/* …sidebar & header omitted… */} {/* Chat canvas */} <CopilotChat className = "h-full p-2" labels={{ initial: initialPrompt }} /> {/* Post previews (rendered after generation) */} <div className = "flex gap-6 mt-6" > <LinkedInPostPreview title = "Generated Title" content = "Generated LinkedIn content…" /> <XPostPreview title = "Generated Title" content = "Generated X content…" /> </div> </div> ) The system & suggestion prompts come from app/prompts/prompts.ts . export const initialPrompt = "Hi! I am a Langgraph x Gemini-powered AI agent capable of performing web search and generating LinkedIn and X (Twitter) posts.\n\n Click on the suggestions to get started." export const suggestionPrompt = "Generate suggestions that revolve around the creation/generation of LinkedIn and X (Twitter) posts on any specific topics." In the full UI code, we also use useCopilotAction to define a generate_post action. This is what lets the agent return structured LinkedIn/X posts, which then render into previews. For simplicity, here’s the trimmed code. import { useCopilotAction } from "@copilotkit/react-core" import { XPostCompact, LinkedInPostCompact } from "@/components/ui/posts" useCopilotAction({ name: "generate_post" , description: "Render a LinkedIn and X post" , parameters: { tweet: { title: "string" , content: "string" }, linkedIn: { title: "string" , content: "string" } }, render: ({ args }) => ( <> {args.tweet?.content && ( <XPostCompact title={args.tweet.title} content={args.tweet.content} /> )} {args.linkedIn?.content && ( <LinkedInPostCompact title={args.linkedIn.title} content={args.linkedIn.content} /> )} </> ) }) For debugging, we also render tool_logs with useCoAgentStateRender , which shows live tool invocations while the agent is working. import { useCoAgentStateRender } from "@copilotkit/react-core" import { ToolLogs } from "@/components/ui/tool-logs" useCoAgentStateRender({ name: "post_generation_agent" , render: ( state ) => ( <ToolLogs logs={state?.state?.tool_logs || []} /> ) }) Here's the final output of the code. I'm not covering the code for basic components like Badge , textarea , x-post , linkedin-post , and button . You can check all the components in the repository at frontend/components/ui . Step 5: Stack Analyzer Agent UI The stack‑analysis page ( frontend/app/stack-analyzer/page.tsx ) hooks into stack_analysis_agent and renders a set of cards. As previously, I have trimmed UI extras like agent switching, quick actions and live tool logs. You can check the code for full UI . It's identical to what we did before, so I'm skipping the explanation of the code. import { CopilotChat, useCopilotChatSuggestions } from "@copilotkit/react-ui" import { initialPrompt1, suggestionPrompt1 } from "../prompts/prompts" import { StackAnalysisCards } from "@/components/ui/stack-analysis-cards" import { ToolLogs } from "@/components/ui/tool-logs" useCoAgentStateRender({ name : "stack_analysis_agent" , render : ( state ) => < ToolLogs logs = {state?.state?.tool_logs || []} /> , }) useCopilotChatSuggestions({ available : "enabled" , instructions : suggestionPrompt1, }) return ( < div className = "…" > {/* …sidebar omitted… */} < CopilotChat className = "h-full p-2" labels = {{ initial: initialPrompt1 }} /> {state.show_cards && < StackAnalysisCards analysis = {state.analysis} /> } </ div > ) The system & suggestion prompts come from app/prompts/prompts.ts . export const initialPrompt1 = 'Hi! I am a Langgraph x Gemini-powered AI agent capable of performing analysis of Public GitHub Repositories.\n\n Click on the suggestions to get started.' export const suggestionPrompt1 = `Generate suggestions that revolve around the analysis of Public GitHub Repositories. Only provide suggestions from these public URLs: [ "https://github.com/freeCodeCamp/freeCodeCamp" , "https://github.com/EbookFoundation/free-programming-books" , "https://github.com/jwasham/coding-interview-university" , "https://github.com/kamranahmedse/developer-roadmap" , "https://github.com/public-apis/public-apis" , "https://github.com/donnemartin/system-design-primer" , "https://github.com/facebook/react" , "https://github.com/tensorflow/tensorflow" , "https://github.com/trekhleb/javascript-algorithms" , "https://github.com/twbs/bootstrap" , "https://github.com/vinta/awesome-python" , "https://github.com/ohmyzsh/ohmyzsh" , "https://github.com/tldr-pages/tldr" , "https://github.com/ytdl-org/youtube-dl" , "https://github.com/taigaio/taiga-back" ]` Here's the final output of the code. I'm not covering the code for basic components like Badge , textarea , stack-analysis-cards , and button . You can check all the components in the repository at frontend/components/ui . 4. Backend Agent Service (FastAPI + CopilotKit SDK) Under the /agent directory lives a FastAPI server that exposes two LangGraph‑based agents. Here's the project structure of the backend again, so it's easier for you to follow the whole layout. agent/ ├── main .py ← FastAPI + CopilotKitSDK wiring ├── posts_generator_agent .py ← “Post Generator” graph & nodes ├── stack_agent .py ← “Stack Analysis” graph & nodes ├── prompts .py ← system prompts ├── pyproject .toml └── agent .py ← Core agent classes and helpers The backend uses Poetry instead of requirements.txt . Install it if you don't have it in your system. pip install poetry Then, inside your agent directory, initialize a new Poetry project using the following command. cd agent poetry init # creates a pyproject.toml here (answer prompts or skip with --no-interaction) This will generate a fresh pyproject.toml and poetry.lock , which means your backend now has its own virtual environment. Most of the AI ecosystem (LangChain, LangGraph, Google SDKs) only supports up to Python 3.12 for now, so make sure to tell Poetry to use a compatible Python version by using this command: poetry env use python3.12 . Then install the dependencies. fastapi : web framework for serving the agent endpoints ( /copilotkit ). uvicorn : the ASGI server used to run FastAPI in production or dev mode. copilotkit : the CopilotKit Python SDK that integrates LangGraph workflows with CopilotKit state streaming. langgraph : state-machine framework for defining agents as graphs of nodes (chat, analyze, end). langchain : provides core abstractions ( RunnableConfig , message types, etc.) used inside nodes. langchain-google-genai : LangChain wrapper for Google Gemini models (e.g. ChatGoogleGenerativeAI ). google-genai : official Google client SDK for Gemini, used for lower-level calls (e.g. genai.Client ). pydantic : schema validation ( StructuredStackAnalysis ) to enforce strict JSON outputs. python-dotenv → loads .env files for managing API keys (like GOOGLE_API_KEY ). Now run the following command to generate a poetry.lock file pinned with exact versions. poetry install FastAPI Server & SDK Setup All agents live behind a single FastAPI server ( agent/main.py ), which mounts them on /copilotkit . from fastapi import FastAPI import uvicorn from copilotkit.integrations.fastapi import add_fastapi_endpoint from copilotkit import CopilotKitSDK, LangGraphAgent from posts_generator_agent import post_generation_graph from stack_agent import stack_analysis_graph app = FastAPI() sdk = CopilotKitSDK( agents=[ LangGraphAgent( name = "post_generation_agent" , description = "An agent that can help with the generation of LinkedIn posts and X posts." , graph =post_generation_graph, ), LangGraphAgent( name = "stack_analysis_agent" , description = "Analyze a GitHub repository URL to infer purpose and tech stack (frontend, backend, DB, infra)." , graph =stack_analysis_graph, ), ] ) add_fastapi_endpoint(app, sdk, "/copilotkit" ) # A simple endpoint to confirm the server is alive @app. get ( "/healthz" ) def health(): return { "status" : "ok" } def main(): "" "Run the uvicorn server." "" port = int(os.getenv( "PORT" , "8000" )) uvicorn. run ( "main:app" , host = "0.0.0.0" , port =port, reload = True , ) if __name__ == "__main__" : main() Here's what's happening behind the scenes: It spins up a FastAPI server Registers two LangGraph agents ( post_generation_agent , stack_analysis_agent ) inside CopilotKit Exposes them on /copilotkit so the frontend can talk to them Runs with Uvicorn 5. Agent Workflows (LangGraph StateGraphs) Both agents are expressed as LangGraph state machines, stitched together with a few async nodes. Every agent file (whether posts_generator_agent.py or stack_agent.py ) follows the same LangGraph skeleton: Define a StateGraph Add nodes (each node = async func…
arrow_backStory search
Story index / copilotkit.ai
Here's How To Build Fullstack Agent Apps (Gemini, CopilotKit & LangGraph) | Blog | CopilotKit
AI agents are getting close to real world applications, but most developers still find it complex to build one. So we are going to build two practical agents: Post Generator that drafts LinkedIn/X content using live web search & Stack Analyzer that inspects GitHub repos and creates structured reports. We will be using Next.js frontend, FastAPI backend, CopilotKit, LangGraph workflows, and Google Gemini. You will find architecture, concepts, prompts, and practical stuff.
Netwrck