A2UI Launched: Full CopilotKit support at launch!

A2UI Launched: CopilotKit has partnered with Google to deliver full support in both CopilotKit and AG-UI!

Check it out
LogoLogo
  • Overview
  • Integrations
  • API Reference
  • Copilot Cloud
Slanted end borderSlanted end border
Slanted start borderSlanted start border
Select integration...

Please select an integration to view the sidebar content.

Generative UI

Agent State

Render the state of your agent with custom UI components.

What is this?

All LangGraph agents are stateful. This means that as your agent progresses through nodes, a state object is passed between them perserving the overall state of a session. CopilotKit allows you to render this state in your application with custom UI components, which we call Agentic Generative UI.

When should I use this?

Rendering the state of your agent in the UI is useful when you want to provide the user with feedback about the overall state of a session. A great example of this is a situation where a user and an agent are working together to solve a problem. The agent can store a draft in its state which is then rendered in the UI.

Implementation

Run and connect your agent

You'll need to run your agent and connect it to CopilotKit before proceeding.

If you don't already have CopilotKit and your agent connected, choose one of the following options:

Define your agent state

LangGraph agents are stateful. As you progress through nodes, a state object is passed between them. CopilotKit allows you to easily render this state in your application.

For the sake of this guide, let's say our state looks like this in our agent.

agent.py
from copilotkit import CopilotKitState # extends MessagesState

# This is the state of the agent, we inherit from CopilotKitState to bind in
# useful helpers when interacting with the agent via CopilotKit.
class AgentState(CopilotKitState):
    searches: list[dict]
agent-js/src/agent.ts
import { Annotation } from "@langchain/langgraph";
import { CopilotKitStateAnnotation } from "@copilotkit/sdk-js/langgraph";

// This is the state of the agent, we inherit from CopilotKitState to bind in
// useful helpers when interacting with the agent via CopilotKit.
export const AgentStateAnnotation = Annotation.Root({
  searches: Annotation<object[]>,
  ...CopilotKitStateAnnotation.spec,
});
export type AgentState = typeof AgentStateAnnotation.State;

Simulate state updates

Next, let's write some logic into our agent that will simulate state updates occurring.

agent.py
import asyncio
from typing import TypedDict
from langchain_core.runnables import RunnableConfig
from langchain_openai import ChatOpenAI
from langchain_core.messages import SystemMessage
from copilotkit import CopilotKitState
from copilotkit.langgraph import copilotkit_emit_state 

class Searches(TypedDict):
    query: str
    done: bool

class AgentState(CopilotKitState):
    searches: list[Searches] = []

async def chat_node(state: AgentState, config: RunnableConfig):
    state["searches"] = [
        {"query": "Initial research", "done": False},
        {"query": "Retrieving sources", "done": False},
        {"query": "Forming an answer", "done": False},
    ]

    # We can call copilotkit_emit_state to emit updated state
    # before a node finishes
    await copilotkit_emit_state(config, state)

    # Simulate state updates
    for search in state["searches"]:
        await asyncio.sleep(1)
        search["done"] = True

        # We can also emit updates in a loop to simulate progress
        await copilotkit_emit_state(config, state)

    # Run the model to generate a response
    response = await ChatOpenAI(model="gpt-4o").ainvoke([
        SystemMessage(content="You are a helpful assistant."),
        *state["messages"],
    ], config)
agent-js/src/agent.ts
import { RunnableConfig } from "@langchain/core/runnables";
import { ChatOpenAI } from "@langchain/openai";
import { Annotation } from "@langchain/langgraph";
import { SystemMessage } from "@langchain/core/messages";
import { copilotkitEmitState, CopilotKitStateAnnotation } from "@copilotkit/sdk-js/langgraph";

type Search = {
  query: string;
  done: boolean;
}

export const AgentStateAnnotation = Annotation.Root({
  searches: Annotation<Search[]>,
  ...CopilotKitStateAnnotation.spec,
});

async function chat_node(state: AgentState, config: RunnableConfig) {
  state.searches = [
    { query: "Initial research", done: false },
    { query: "Retrieving sources", done: false },
    { query: "Forming an answer", done: false },
  ];

  // We can call copilotkit_emit_state to emit updated state
  // before a node finishes
  await copilotkitEmitState(config, state);

  // Simulate state updates
  for (const search of state.searches) {
    await new Promise(resolve => setTimeout(resolve, 1000));
    search.done = true;

    // We can also emit updates in a loop to simulate progress
    await copilotkitEmitState(config, state);
  }

  const response = await new ChatOpenAI({ model: "gpt-4o" }).invoke([
    new SystemMessage({ content: "You are a helpful assistant."}),
    ...state.messages,
  ], config);

Render state of the agent in the chat

Now we can utilize useCoAgentStateRender to render the state of our agent in the chat.

app/page.tsx
import { useCoAgentStateRender } from "@copilotkit/react-core";

// For type safety, redefine the state of the agent. If you're using
// using LangGraph JS you can import the type here and share it.
type AgentState = {
  searches: {
    query: string;
    done: boolean;
  }[];
};

function YourMainContent() {
  // ...

  // styles omitted for brevity
  useCoAgentStateRender<AgentState>({
    name: "sample_agent", // the name the agent is served as
    render: ({ state }) => (
      <div>
        {state.searches?.map((search, index) => (
          <div key={index}>
            {search.done ? "✅" : "❌"} {search.query}{search.done ? "" : "..."}
          </div>
        ))}
      </div>
    ),
  });

  // ...

  return <div>...</div>;
}

Render state outside of the chat

You can also render the state of your agent outside of the chat. This is useful when you want to render the state of your agent anywhere other than the chat.

app/page.tsx
import { useCoAgent } from "@copilotkit/react-core"; 
// ...

// Define the state of the agent, should match the state of the agent in your LangGraph.
type AgentState = {
  searches: {
    query: string;
    done: boolean;
  }[];
};

function YourMainContent() {
  // ...

  const { state } = useCoAgent<AgentState>({
    name: "sample_agent", // the name the agent is served as
  })

  // ...

  return (
    <div>
      {/* ... */}
      <div className="flex flex-col gap-2 mt-4">
        {state.searches?.map((search, index) => (
          <div key={index} className="flex flex-row">
            {search.done ? "✅" : "❌"} {search.query}
          </div>
        ))}
      </div>
    </div>
  )
}

Give it a try!

You've now created a component that will render the agent's state in the chat.

PREV
Frontend Tools
Slanted end borderSlanted end border
Slanted start borderSlanted start border
NEXT
Human in the Loop (HITL)

On this page

What is this?
When should I use this?
Implementation
Run and connect your agent
Define your agent state
Simulate state updates
Render state of the agent in the chat
Render state outside of the chat
Give it a try!