Skip to content

Commit 387120d

Browse files
authored
docs: port AG2 integration docs to AG-UI backend examples (CopilotKit#3151)
1 parent a48236b commit 387120d

23 files changed

Lines changed: 1792 additions & 543 deletions

File tree

docs/content/docs/integrations/ag2/(other)/contributing/code-contributions/index.mdx

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ Now that you've made your changes, commit and push them. Then, simply head over
105105

106106
CopilotKit contains a ready-made script for starting a development environment based on one of the CoAgent examples. It lets you work on CopilotKit internals in the core Typescript and Python code while seeing your changes applied to the chosen example.
107107

108-
As a prerequisite, make sure you have GNU parallel and langgraph CLI installed.
108+
As a prerequisite, make sure you have GNU parallel and the runtime CLI installed.
109109

110110
Next, go to the `CopilotKit/` directory and run the `example.sh` script for the example you want to work on:
111111

@@ -115,12 +115,6 @@ Next, go to the `CopilotKit/` directory and run the `example.sh` script for the
115115

116116
This will start a development environment with hot reload.
117117

118-
You can optionally run the same example on LangGraph platform by running:
119-
120-
```bash
121-
./scripts/develop/example.sh coagents-starter langgraph-platform
122-
```
123-
124118
## Debugging
125119

126120
Every time you run CopilotKit on localhost, you will be able to see the **CopilotKit Dev Console** in the chat window. The Dev Console provides you with useful functionality to debug your copilot (e.g. see what state the copilot is aware of, actions it can perform, etc).

docs/content/docs/integrations/ag2/agentic-chat-ui.mdx

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,61 @@ import { UserIcon, PaintbrushIcon, WrenchIcon, RepeatIcon } from "lucide-react";
2929
Agentic chat UIs are ways for your users to interact with your agent. CopilotKit provides a variety of different components to choose from, each
3030
with their own unique use cases.
3131

32-
If you've gone through the [quick start guide](/ag2/quickstart) **you already have a agentic chat UI setup**! Nothing else is needed
32+
If you've gone through the [quickstart guide](/ag2/quickstart) **you already have a agentic chat UI setup**! Nothing else is needed
3333
to get started.
3434

35+
<Callout type="info">
36+
CopilotKit consumes AG-UI protocol events streamed by AG2 over <code>/chat</code>. See the <a href="https://docs.ag2.ai/latest/docs/user-guide/ag-ui/" target="_blank">AG2 AG-UI integration docs</a>.
37+
</Callout>
38+
3539
## When should I use this?
3640

3741
CopilotKit provides a variety of different batteries-included components to choose from to create agent native applications. They scale
3842
from simple chat UIs to completely custom applications.
3943

40-
<ComponentExamples components={props.components} />
44+
<ComponentExamples components={props.components} />
45+
46+
## Implementation
47+
48+
**AG2 backend over AG-UI:** Use AG2's `AGUIStream` with a FastAPI `/chat` endpoint to stream protocol events to CopilotKit.
49+
This follows the same pattern used in the <a href="https://github.com/ag2ai/ag2-samples" target="_blank">AG2 samples repo</a> (`weather.py`), adapted to `/chat` with token-header auth.
50+
51+
```python title="agent.py"
52+
from fastapi import FastAPI, Header, HTTPException
53+
from fastapi.responses import StreamingResponse
54+
from autogen import ConversableAgent, LLMConfig
55+
from autogen.ag_ui import AGUIStream, RunAgentInput
56+
57+
agent = ConversableAgent(
58+
name="assistant",
59+
system_message="You are a helpful assistant.",
60+
llm_config=LLMConfig({"model": "gpt-4o-mini"}),
61+
)
62+
63+
@agent.register_for_llm(description="A tiny backend tool example.")
64+
def ping(topic: str) -> str:
65+
return f"pong: {topic}"
66+
67+
stream = AGUIStream(agent)
68+
app = FastAPI()
69+
70+
@app.post("/chat")
71+
async def run_agent(
72+
message: RunAgentInput,
73+
accept: str | None = Header(None),
74+
authorization: str | None = Header(None),
75+
):
76+
if not authorization:
77+
raise HTTPException(status_code=401, detail="Missing authorization header")
78+
79+
return StreamingResponse(
80+
stream.dispatch(message, accept=accept),
81+
media_type=accept or "text/event-stream",
82+
)
83+
```
84+
85+
If you handle auth upstream, you can also mount the endpoint directly:
86+
87+
```python title="agent.py"
88+
app.mount("/chat", stream.build_asgi())
89+
```
Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
---
2+
title: "Authentication"
3+
icon: "lucide/Shield"
4+
description: "Secure your AG2 backend with user authentication on /chat"
5+
---
6+
7+
## Overview
8+
9+
CopilotKit supports user authentication for AG2 backends in two deployment modes:
10+
11+
- **LangGraph Platform equivalent**: managed runtime forwarding to your AG2 `/chat` endpoint
12+
- **Self-hosted runtime**: your own CopilotKit runtime forwarding to your AG2 `/chat` endpoint
13+
14+
Both approaches let your AG2 backend access authenticated user context and enforce authorization.
15+
16+
This pattern enables your backend to:
17+
18+
- Validate user tokens before dispatching the agent
19+
- Attach authenticated user context to agent state/tools
20+
- Enforce authorization decisions server-side
21+
22+
<Callout type="info">
23+
CopilotKit consumes AG-UI protocol events streamed by AG2 over <code>/chat</code>. See the <a href="https://docs.ag2.ai/latest/docs/user-guide/ag-ui/" target="_blank">AG2 AG-UI integration docs</a>.
24+
</Callout>
25+
26+
## How It Works
27+
28+
```mermaid
29+
sequenceDiagram
30+
participant Frontend
31+
participant CopilotKit
32+
participant AG2Backend
33+
participant Agent
34+
35+
Frontend->>CopilotKit: authorization: "user-token"
36+
CopilotKit->>AG2Backend: Forward auth token header
37+
AG2Backend->>AG2Backend: Validate token
38+
AG2Backend->>Agent: Dispatch with authenticated context
39+
Agent->>Agent: Access authenticated user context
40+
```
41+
42+
## Frontend Setup
43+
44+
Pass your authentication token via the `properties` prop:
45+
46+
```tsx
47+
<CopilotKit
48+
runtimeUrl="/api/copilotkit"
49+
properties={{
50+
authorization: userToken, // forwarded to AG2 /chat
51+
}}
52+
>
53+
<YourApp />
54+
</CopilotKit>
55+
```
56+
57+
**Note**: The `authorization` property is forwarded to your AG2 `/chat` endpoint as a request header.
58+
59+
## LangGraph Platform Deployment
60+
61+
**For managed deployments**, protect your AG2 `/chat` endpoint with token-header validation.
62+
63+
### Setup Authentication Handler
64+
65+
```python
66+
from fastapi import FastAPI, Header, HTTPException
67+
from fastapi.responses import StreamingResponse
68+
from autogen import ConversableAgent, LLMConfig
69+
from autogen.ag_ui import AGUIStream, RunAgentInput
70+
71+
agent = ConversableAgent(
72+
name="assistant",
73+
system_message="You are a helpful assistant.",
74+
llm_config=LLMConfig({"model": "gpt-4o-mini"}),
75+
)
76+
77+
stream = AGUIStream(agent)
78+
app = FastAPI()
79+
80+
def validate_your_token(token: str) -> dict:
81+
# Replace this with your own validation logic.
82+
if token != "valid-token":
83+
raise HTTPException(status_code=401, detail="Unauthorized")
84+
return {"user_id": "user_123", "role": "member"}
85+
86+
@app.post("/chat")
87+
async def run_agent(
88+
message: RunAgentInput,
89+
accept: str | None = Header(None),
90+
authorization: str | None = Header(None),
91+
):
92+
if not authorization:
93+
raise HTTPException(status_code=401, detail="Missing authorization header")
94+
95+
token = authorization.replace("Bearer ", "")
96+
user_info = validate_your_token(token)
97+
98+
# Use user_info to scope tools, state, and data access before dispatch.
99+
return StreamingResponse(
100+
stream.dispatch(message, accept=accept),
101+
media_type=accept or "text/event-stream",
102+
)
103+
```
104+
105+
### Access User in Agent
106+
107+
Use validated user identity to scope tool calls and data access:
108+
109+
```python
110+
from typing import Annotated
111+
from autogen import ContextVariables
112+
113+
@agent.register_for_llm(description="Return account data for the authenticated user.")
114+
def get_account_data(
115+
context: ContextVariables,
116+
account_id: Annotated[str, "The target account id"],
117+
) -> dict:
118+
user = context.get("auth_user")
119+
if not user:
120+
return {"error": "unauthorized"}
121+
# Example check: ensure user can access this account
122+
if account_id not in user.get("allowed_accounts", []):
123+
return {"error": "forbidden"}
124+
return {"account_id": account_id, "owner": user["user_id"]}
125+
```
126+
127+
## Self-hosted Deployment
128+
129+
**For self-hosted deployments**, use the same `/chat` header-validation pattern in your own FastAPI service.
130+
131+
### Setup Dynamic Agent Configuration
132+
133+
```python
134+
from fastapi import FastAPI, Header, HTTPException
135+
from fastapi.responses import StreamingResponse
136+
from autogen import ConversableAgent, LLMConfig
137+
from autogen.ag_ui import AGUIStream, RunAgentInput
138+
139+
agent = ConversableAgent(
140+
name="assistant",
141+
system_message="You are a helpful assistant.",
142+
llm_config=LLMConfig({"model": "gpt-4o-mini"}),
143+
)
144+
145+
stream = AGUIStream(agent)
146+
app = FastAPI()
147+
148+
@app.post("/chat")
149+
async def run_agent(
150+
message: RunAgentInput,
151+
accept: str | None = Header(None),
152+
authorization: str | None = Header(None),
153+
):
154+
if not authorization:
155+
raise HTTPException(status_code=401, detail="Unauthorized")
156+
# Validate token here, then dispatch
157+
return StreamingResponse(
158+
stream.dispatch(message, accept=accept),
159+
media_type=accept or "text/event-stream",
160+
)
161+
```
162+
163+
### Access User in Agent
164+
165+
After token validation, persist user identity in request-scoped context and enforce access checks in AG2 tools/state reads.
166+
167+
## Universal Authentication Pattern
168+
169+
For backends that run in both managed and self-hosted modes, use this pattern:
170+
171+
```python
172+
def extract_user_from_auth_header(authorization: str | None) -> dict | None:
173+
if not authorization:
174+
return None
175+
token = authorization.replace("Bearer ", "")
176+
return validate_your_token(token)
177+
```
178+
179+
Then:
180+
181+
- Read `authorization` on `/chat`
182+
- Validate token before `stream.dispatch(...)`
183+
- Attach user context for tool/state authorization
184+
- Deny unauthorized or out-of-scope access
185+
186+
## Security Notes
187+
188+
### LangGraph Platform
189+
190+
- **Token Validation**: Validate tokens on your AG2 `/chat` endpoint
191+
- **User Scoping**: Scope data access by authenticated user identity
192+
193+
### Self-hosted
194+
195+
- **Manual Validation**: Implement and maintain your own validation logic
196+
- **Header Forwarding**: Ensure your runtime forwards `authorization` to AG2
197+
198+
### General Best Practices
199+
200+
- **Permission Checks**: Enforce role-based checks in AG2 tools
201+
- **Transport Security**: Serve `/chat` over HTTPS
202+
- **Least Privilege**: Return only data needed for the current user/task
203+
204+
## Troubleshooting
205+
206+
### Common Issues
207+
208+
**Token not reaching backend**:
209+
210+
- Ensure you're passing `authorization` in `properties`
211+
- Confirm your runtime forwards headers to AG2 `/chat`
212+
213+
**Invalid token format**:
214+
215+
- Handle both raw tokens and `Bearer <token>` formats consistently
216+
217+
**Unexpected anonymous access**:
218+
219+
- Verify `authorization` checks happen before calling `stream.dispatch(...)`
220+
221+
## Next Steps
222+
223+
- [Configure chat UI with AG2 backend ->](/ag2/agentic-chat-ui)
224+
- [Learn about shared state ->](/ag2/shared-state)
225+
- [Implement human-in-the-loop workflows ->](/ag2/human-in-the-loop)

0 commit comments

Comments
 (0)