> ## Documentation Index
> Fetch the complete documentation index at: https://docs.crewai.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Agentic Generative UI

> Render your CrewAI Flow's live state as UI that updates as the agent works through multi-step tasks.

## Render the agent's live state

Some work does not fit into a single tool call. A research task, a multi-step plan, a long-running job: the interesting thing to show the user is not one result, but *progress*. Agentic generative UI renders the agent's **state** and re-renders it every time that state changes.

The pattern has two halves:

1. Your Flow writes progress into its own state as it works.
2. Your frontend reads that state with `useAgent` and paints it, re-rendering as the state streams in.

The Flow's state reaches the frontend over AG-UI without you wiring up any transport. A state snapshot is emitted automatically at each step (method) boundary of the Flow, and you can push intermediate updates during a long-running step by calling `copilotkit_emit_state` explicitly. You subclass the state to add your own fields, update them in the Flow, and read them in React.

<Note>
  State-driven rendering requires a **Flow** with custom state (`Flow[AgentState]`). Crews are chat-oriented and do not expose custom state this way, so with a Crew use [tool rendering](/en/guides/frontend/tool-based-generative-ui) instead.
</Note>

## Build a live task planner

This example builds a planner that breaks a request into about ten steps and streams them to the UI as a checklist. It assumes you already have a CrewAI server and a CopilotKit frontend wired up. If you do not, start with the [Frontend Overview](/en/guides/frontend/overview).

<Steps>
  <Step title="Add your own fields to the agent state">
    Subclass `CopilotKitState` to declare the state your UI needs. `CopilotKitState` already carries the conversation (`messages`); you add whatever else you want to render, here a list of task steps.

    ```python theme={null}
    from typing import List, Literal
    from pydantic import BaseModel, Field
    from ag_ui_crewai.sdk import CopilotKitState


    class TaskStep(BaseModel):
        description: str
        status: Literal["enabled", "disabled"]


    class AgentState(CopilotKitState):
        steps: List[TaskStep] = Field(default_factory=list)
    ```

    Everything on `AgentState` is included in the state snapshot the frontend receives. A snapshot is emitted automatically at each step boundary, so writing to `self.state` is enough for the UI to pick it up between steps. To update the UI *during* a long step, emit explicitly (shown below).
  </Step>

  <Step title="Write progress into state from the Flow">
    Type your Flow with the custom state (`Flow[AgentState]`) and let the model fill it in. Here the LLM calls a `generate_task_steps` tool; the streamed tool call lands in the conversation and the steps become visible in state.

    ```python theme={null}
    from crewai.flow.flow import Flow, start
    from litellm import acompletion
    from ag_ui_crewai.sdk import copilotkit_stream

    GENERATE_TASK_STEPS_TOOL = {
        "type": "function",
        "function": {
            "name": "generate_task_steps",
            "description": "Break a task into about 10 short imperative steps.",
            "parameters": {
                "type": "object",
                "properties": {
                    "steps": {
                        "type": "array",
                        "items": {
                            "type": "object",
                            "properties": {
                                "description": {"type": "string"},
                                "status": {"type": "string", "enum": ["enabled"]},
                            },
                            "required": ["description", "status"],
                        },
                    },
                },
                "required": ["steps"],
            },
        },
    }


    class TaskPlannerFlow(Flow[AgentState]):
        @start()
        async def chat(self):
            response = await copilotkit_stream(
                await acompletion(
                    model="openai/gpt-4o",
                    messages=[
                        {"role": "system", "content": "Plan the task the user asks for."},
                        *self.state.messages,
                    ],
                    tools=[GENERATE_TASK_STEPS_TOOL],
                    parallel_tool_calls=False,
                    stream=True,
                )
            )
            message = response.choices[0].message
            self.state.messages.append(message)
    ```

    Wrapping the LLM call in `copilotkit_stream` streams the assistant's tokens and tool call to the frontend as they are produced. The `steps` you write to `self.state` are sent in the state snapshot emitted at the end of this step.
  </Step>

  <Step title="Stream progress during a long step (optional)">
    The automatic snapshot fires at step boundaries. If a single step does substantial work and you want the checklist to fill in *as it happens*, emit intermediate state yourself with `copilotkit_emit_state`. Each call pushes the current state to the frontend immediately.

    ```python theme={null}
    from ag_ui_crewai.sdk import copilotkit_emit_state

    class TaskPlannerFlow(Flow[AgentState]):
        @start()
        async def execute(self):
            for step in self.state.steps:
                step.status = "disabled"          # mark done as you go
                await copilotkit_emit_state(self.state)   # push update now
                await do_work(step)
    ```

    Import `copilotkit_emit_state` from `ag_ui_crewai.sdk`. It requires the CopilotKit SDK (`pip install "copilotkit[crewai]"`). Reach for it only when a step is long enough that waiting for its boundary snapshot would feel unresponsive.
  </Step>

  <Step title="Serve the Flow over AG-UI">
    Register the Flow exactly as any other, on its own path:

    ```python theme={null}
    # server.py
    from fastapi import FastAPI
    from ag_ui_crewai.endpoint import add_crewai_flow_fastapi_endpoint
    from my_agents.task_planner import TaskPlannerFlow

    app = FastAPI(title="CrewAI Agent Server")

    add_crewai_flow_fastapi_endpoint(
        app=app,
        flow=TaskPlannerFlow(),
        path="/task_planner",
    )
    ```

    See the [Frontend Overview](/en/guides/frontend/overview) for the full server, runtime, and provider setup, and remember to register the agent (here `task_planner`) in your CopilotKit runtime route.
  </Step>

  <Step title="Read the live state in React">
    On the frontend, `useAgent` gives you the agent's live state. Subscribe to state changes so your component re-renders every time the Flow writes an update.

    ```tsx theme={null}
    "use client";
    import { useAgent, UseAgentUpdate } from "@copilotkit/react-core/v2";

    function TaskPlan() {
      const { agent } = useAgent({
        agentId: "task_planner",
        updates: [UseAgentUpdate.OnStateChanged],
      });

      const steps = agent?.state?.steps ?? [];

      return (
        <ul>
          {steps.map((s, i) => (
            <li key={i}>{s.description}</li>
          ))}
        </ul>
      );
    }
    ```

    `useAgent` returns `{ agent }`. A few things to know:

    * `agent.state` is the live Flow state. Its shape matches the fields you added to `AgentState`, so `agent.state.steps` is your list of task steps.
    * `agent.isRunning` tells you when the agent is actively working, useful for showing a spinner or disabling input.
    * `updates: [UseAgentUpdate.OnStateChanged]` re-renders the component whenever state changes, so the checklist fills in as the Flow streams its steps.
  </Step>
</Steps>

## Where this goes next

Reading state is the foundation. Two guides build directly on it:

* [Shared State](/en/guides/frontend/shared-state) adds the other direction: editing the agent's state from the UI and having the Flow pick up the change.
* [Predictive State](/en/guides/frontend/predictive-state-updates) streams a tool's in-progress arguments into state so the UI reflects work before it is committed.

## Related

<CardGroup cols={2}>
  <Card title="Shared State" icon="arrows-rotate" href="/en/guides/frontend/shared-state">
    Sync agent state and app UI in both directions.
  </Card>

  <Card title="Predictive State" icon="gauge-high" href="/en/guides/frontend/predictive-state-updates">
    Stream in-progress tool arguments into state.
  </Card>

  <Card title="Tool-Based Generative UI" icon="puzzle-piece" href="/en/guides/frontend/tool-based-generative-ui">
    Map agent tool calls to components.
  </Card>
</CardGroup>
