showcase/shell-docs/src/content/docs/integrations/adk/generative-ui/state-rendering.mdx
{/_ <IframeSwitcher id="agent-state-example" exampleUrl="https://feature-viewer.copilotkit.ai/adk-middleware/feature/agentic_generative_ui?sidebar=false&chatDefaultOpen=false" codeUrl="https://feature-viewer.copilotkit.ai/adk-middleware/feature/agentic_generative_ui?view=code&sidebar=false&codeLayout=tabs" exampleLabel="Demo" codeLabel="Code" height="700px" /> _/}
All ADK 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.
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.
Create your ADK agent with a stateful structure. Here's a complete example that tracks language selection:
```python title="agent.py"
from typing import Dict
from fastapi import FastAPI
from pydantic import BaseModel
from ag_ui_adk import ADKAgent, add_adk_fastapi_endpoint
from google.adk.agents import LlmAgent
from google.adk.tools import ToolContext
class AgentState(BaseModel):
"""State for the agent."""
language: str = "english"
def set_language(tool_context: ToolContext, new_language: str) -> Dict[str, str]:
"""Sets the language preference for the user.
Args:
tool_context (ToolContext): The tool context for accessing state.
new_language (str): The language to save in state.
Returns:
Dict[str, str]: A dictionary indicating success status and message.
"""
tool_context.state["language"] = new_language
return {"status": "success", "message": f"Language set to {new_language}"}
agent = LlmAgent(
name="my_agent",
model="gemini-2.5-flash",
instruction="You are a helpful assistant that can change language settings.",
tools=[set_language],
)
adk_agent = ADKAgent(
adk_agent=agent,
app_name="demo_app",
user_id="demo_user",
session_timeout_seconds=3600,
use_in_memory_services=True,
)
app = FastAPI()
add_adk_fastapi_endpoint(app, adk_agent, path="/")
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8000)
```
```tsx title="app/page.tsx"
// ...
// ...
// Define the state of the agent, should match the state of your ADK Agent.
type AgentState = {
language: string;
};
function YourMainContent() {
// ...
// [!code highlight:13]
// styles omitted for brevity
useAgent({
agentId: "my_agent",
render: ({ state }) => (
<div>
Current language: {state.language || 'not set'}
</div>
),
});
// ...
return <div>...</div>;
}
```
<Callout type="warn" title="Important">
The `name` parameter must exactly match the agent name you defined in your CopilotRuntime configuration (e.g., `my_agent` from the quickstart).
</Callout>
```tsx title="app/page.tsx"
// ...
// Define the state of the agent, should match the state of your ADK Agent.
type AgentState = {
language: string;
};
function YourMainContent() {
// ...
// [!code highlight:3]
const { agent } = useAgent({
agentId: "my_agent",
})
// ...
return (
<div>
<div className="flex flex-col gap-2 mt-4">
Current language: {agent.state?.language || 'not set'}
</div>
</div>
)
}
```
<Callout type="warn" title="Important">
The `name` parameter must exactly match the agent name you defined in your CopilotRuntime configuration (e.g., `my_agent` from the quickstart).
</Callout>
You've now created a component that will render the agent's state in the chat.
<video
src="https://cdn.copilotkit.ai/docs/copilotkit/images/coagents/agentic-generative-ui.mp4"
className="rounded-lg shadow-xl"
loop
playsInline
controls
autoPlay
muted
/>