React đến AG-UI Agent
Nx Plugin for AWS cung cấp một generator để kết nối trang web React với Agent mà expose giao thức AG-UI. Nó kết nối CopilotKit với một @ag-ui/client HttpAgent trên trang web của bạn, với hỗ trợ xác thực AWS IAM và Cognito.
Điều kiện tiên quyết
Phần tiêu đề “Điều kiện tiên quyết”Trước khi sử dụng generator này, hãy đảm bảo bạn có:
- Một trang web React (được tạo bằng generator
ts#website) - Một TypeScript hoặc Python Agent với
protocol=ag-ui(được tạo bằng generatorts#agenthoặcpy#agent) - Đối với các agent đã triển khai, Cognito Auth được thêm qua generator
ts#website#auth
Cách sử dụng
Phần tiêu đề “Cách sử dụng”Chạy Generator
Phần tiêu đề “Chạy Generator”Chạy generator này@aws/nx-plugin:connection
pnpm nx g @aws/nx-plugin:connection yarn nx g @aws/nx-plugin:connection npx nx g @aws/nx-plugin:connection bunx nx g @aws/nx-plugin:connection- Cài đặt Nx Console VSCode Plugin nếu bạn chưa cài đặt
- Mở Nx Console trong VSCode
- Nhấp
Generate (UI)trong phần "Common Nx Commands" - Tìm kiếm
@aws/nx-plugin - connection - Điền các tham số bắt buộc
- Nhấp
Generate
Xây dựng lệnh của bạn5
Bắt buộc
Bắt buộc
Bạn sẽ được nhắc chọn trang web React của mình làm source project và project chứa AG-UI Agent của bạn làm target project. Nếu target project của bạn chứa nhiều component (chẳng hạn như nhiều agent hoặc các loại component khác), bạn sẽ được nhắc chỉ định một targetComponent để phân biệt.
targetComponent chấp nhận --name mà bạn đã cung cấp cho agent generator ở bất kỳ dạng viết hoa nào (StoryAgent, story-agent), đường dẫn của component tương đối với thư mục gốc của target project, hoặc generator id của nó.
Tùy chọn
Phần tiêu đề “Tùy chọn”sourceProjectBắt buộcstringDự án nguồn
targetProjectBắt buộcstringDự án đích để kết nối tới
sourceComponentstringComponent nguồn để kết nối từ đó (tên component, đường dẫn tương đối so với thư mục gốc của dự án nguồn, hoặc id của generator). Sử dụng '.' để chọn rõ ràng dự án làm nguồn.
targetComponentstringComponent đích để kết nối tới (tên component, đường dẫn tương đối so với thư mục gốc của dự án đích, hoặc id của generator). Sử dụng '.' để chọn rõ ràng dự án làm đích.
preferInstallDependenciesbooleanMặc định:trueCó nên cài đặt các dependencies sau khi generator chạy hay không. Đặt thành false để trì hoãn việc cài đặt khi chạy nhiều generator liên tiếp (việc cài đặt vẫn sẽ chạy nếu cần thiết để các generator tiếp theo có thể tính toán Nx project graph); cài đặt một lần vào cuối.
Đầu ra của Generator
Phần tiêu đề “Đầu ra của Generator”Generator tạo ra một component AguiProvider được chia sẻ duy nhất, một hook cho mỗi agent được kết nối, và một wrapper có theme cho các component chat của CopilotKit:
Thư mụcsrc
Thư mụccomponents
- AguiProvider.tsx
CopilotKitProviderduy nhất cho mọi AG-UI agent. Được tạo trong lần chạyconnectionđầu tiên và được cập nhật trong các lần chạy tiếp theo để đăng ký từng agent mới. - <agent-name>-chat.tsx Một
<AgentName>Chatcó theme được liên kết với id của agent này. Một file cho mỗi lần chạyconnection. Thư mụccopilot
- index.tsx Re-export
CopilotChat,CopilotSidebarvàCopilotPopupvới các slot mặc định khớp vớiuxcủa trang web của bạn (Cloudscape, Shadcn, hoặc không có theme). - ThemeComponents .tsx Các component theme theo từng slot (ví dụ:
CloudscapeAssistantMessage.tsx,ShadcnChatInput.tsx). Chỉ được cung cấp khiuxlàcloudscapehoặcshadcn.
- index.tsx Re-export
- AguiProvider.tsx
Thư mụchooks
- useAgui<AgentName>.tsx Đăng ký một AG-UI agent và export id của nó dưới dạng
<AGENT_NAME>_ID. Một file cho mỗi lần chạyconnection. - useSigV4.tsx Ký SigV4 (chỉ IAM)
- useAgui<AgentName>.tsx Đăng ký một AG-UI agent và export id của nó dưới dạng
Chạy connection lần thứ hai cho một agent khác thêm một hook useAgui<AgentName>.tsx mới và component <agent-name>-chat.tsx và cập nhật AguiProvider.tsx để đăng ký cả hai hook — mọi chỉnh sửa tùy chỉnh mà bạn đã thực hiện đối với provider đều được giữ nguyên. main.tsx giữ wrapper <AguiProvider> duy nhất của nó — bạn sẽ không bao giờ có các provider lồng nhau.
Các dependency sau được thêm vào package.json gốc:
@copilotkit/react-core— cung cấpCopilotKitProvidervà các component chat (CopilotChat,CopilotSidebar,CopilotPopup)@ag-ui/client—HttpAgentđược sử dụng bởi các hook được tạoaws4fetch,oidc-client-ts,react-oidc-context,@aws-sdk/credential-providers— chỉ xác thực IAMreact-oidc-context— xác thực Cognito
Cách hoạt động
Phần tiêu đề “Cách hoạt động”Kết nối AG-UI
Phần tiêu đề “Kết nối AG-UI”Mỗi hook useAgui<AgentName> đọc giá trị runtime của agent từ Runtime Configuration và khởi tạo một @ag-ui/client HttpAgent:
- Đã triển khai: giá trị runtime là một Bedrock AgentCore Runtime ARN, được chuyển đổi thành endpoint HTTPS của AgentCore:
https://bedrock-agentcore.<region>.amazonaws.com/runtimes/<encoded-arn>/invocations?qualifier=DEFAULT - Phát triển cục bộ:
devghi đè giá trị thành URL cục bộ của agent (ví dụ:http://localhost:8081)
AguiProvider được chia sẻ gọi mọi hook được tạo và spread từng hook vào selfManagedAgents trên một CopilotKitProvider duy nhất, expose tất cả chúng cho các component CopilotKit.
Tích hợp CopilotKit
Phần tiêu đề “Tích hợp CopilotKit”CopilotKit là React client tham chiếu chính thức cho giao thức AG-UI và đi kèm với các component chat sẵn có:
<CopilotChat />— giao diện chat đầy đủ<CopilotSidebar />— chat panel bên cố định<CopilotPopup />— popup chat nổi
Đặt bất kỳ component nào trong số này ở bất kỳ đâu bên trong wrapper <AguiProvider> (đã được kết nối vào main.tsx cho bạn).
Xác thực
Phần tiêu đề “Xác thực”Code được tạo xử lý xác thực tùy thuộc vào cấu hình của agent:
- IAM (mặc định): sử dụng các HTTP request được ký AWS SigV4. Thông tin xác thực được lấy từ Cognito Identity Pool được cấu hình với auth của trang web của bạn.
- Cognito: nhúng JWT access token vào header
Authorizationdưới dạng Bearer token.
Sessions và Threads
Phần tiêu đề “Sessions và Threads”AG-UI và AgentCore Runtime mỗi cái xác định một cuộc hội thoại theo cách khác nhau, và hook được tạo liên kết chúng lại với nhau:
threadId— định danh cuộc hội thoại AG-UI, được gửi trong request body. CopilotKit tạo một UUID ngẫu nhiên cho mỗi cuộc trò chuyện trừ khi bạn truyền mộtthreadIdrõ ràng.- Session ID — session AgentCore Runtime, được gửi trong header
X-Amzn-Bedrock-AgentCore-Runtime-Session-Id. Nó chọn microVM phục vụ request, và là thứ màsession.ts/session.pycủa agent của bạn dùng làm khóa cho trạng thái cuộc hội thoại.
Hook suy ra session ID từ thread ID, đệm phải nó đến 33 ký tự mà AgentCore Runtime yêu cầu:
function agentCoreSessionId(input: RunAgentInput): string { return (input.threadId ?? '').padEnd(33, '0');}Để threadId không được đặt là đơn giản nhất — UUID được tạo bởi CopilotKit đã có 36 ký tự. Nếu bạn truyền một cách rõ ràng, hãy đảm bảo nó có ít nhất 33 ký tự, vì việc đệm ánh xạ các thread ID chỉ khác nhau ở các ký tự cuối vào cùng một session.
Cả Session ID và Thread ID đều được cung cấp bởi trình duyệt. Để hạn chế mỗi người dùng chỉ truy cập các cuộc hội thoại của riêng họ, hãy tham khảo hướng dẫn py#agent hoặc ts#agent.
Hạ tầng
Phần tiêu đề “Hạ tầng”Nếu agent của bạn sử dụng xác thực IAM, vai trò được xác thực của Cognito Identity Pool phải được cấp quyền để gọi agent.
const identity = new UserIdentity(this, 'Identity');const myAgent = new MyAgent(this, 'MyAgent');
// Grant the authenticated Cognito role permission to invoke the agentmyAgent.grantInvokeAccess(identity.identityPool.authenticatedRole);grantInvokeAccess kết nối tất cả các hành động gọi AgentCore (InvokeAgentRuntime, InvokeAgentRuntimeWithWebSocketStream) trên ARN runtime của agent.
module "identity" { source = "../../common/terraform/src/core/user-identity"}
module "my_agent" { source = "../../common/terraform/src/app/agents/my-agent"
appconfig_application_id = module.runtime_config_appconfig.application_id appconfig_application_arn = module.runtime_config_appconfig.application_arn}
# Grant the authenticated Cognito role permission to invoke the agentresource "aws_iam_policy" "invoke_my_agent" { name = "InvokeMyAgentPolicy" policy = jsonencode({ Version = "2012-10-17" Statement = [{ Effect = "Allow" Action = [ "bedrock-agentcore:InvokeAgentRuntime", "bedrock-agentcore:InvokeAgentRuntimeWithWebSocketStream", ] Resource = [ module.my_agent.agent_core_runtime_arn, "${module.my_agent.agent_core_runtime_arn}/*", ] }] })}
resource "aws_iam_role_policy_attachment" "invoke_my_agent" { role = module.identity.authenticated_role_name policy_arn = aws_iam_policy.invoke_my_agent.arn}Nếu agent của bạn sử dụng xác thực Cognito, bạn không cần định nghĩa thêm bất kỳ cơ sở hạ tầng nào để kết nối website của bạn với agent.
Sử dụng Code được tạo
Phần tiêu đề “Sử dụng Code được tạo”Thêm giao diện Chat
Phần tiêu đề “Thêm giao diện Chat”Generator cung cấp một component <AgentName>Chat cho mỗi agent được kết nối, đã được liên kết với id của agent đó và có theme khớp với ux của trang web của bạn. Đặt nó ở bất kỳ đâu bên trong wrapper <AguiProvider>:
import { StoryAgentChat } from './components/story-agent-chat';
function ChatPage() { return ( <StoryAgentChat labels={{ welcomeMessageText: 'How can I help you today?', chatInputPlaceholder: 'Ask me anything...', }} /> );}Nó chuyển tiếp mọi prop của CopilotChat ngoại trừ agentId, vì vậy bất cứ thứ gì bạn có thể truyền cho <CopilotChat /> đều hoạt động ở đây.
Kết nối nhiều AG-UI Agent
Phần tiêu đề “Kết nối nhiều AG-UI Agent”Chạy generator connection một lần cho mỗi agent. Mỗi lần chạy cung cấp component chat riêng của agent đó, vì vậy việc định tuyến một cuộc trò chuyện đến một agent cụ thể là vấn đề của component nào bạn render:
import { StoryAgentChat } from './components/story-agent-chat';import { ResearchAgentChat } from './components/research-agent-chat';
<StoryAgentChat /> {/* talks to StoryAgent */}<ResearchAgentChat /> {/* talks to ResearchAgent */}Nếu bạn cần id thô — để gọi các hook riêng của CopilotKit chẳng hạn — mỗi hook được tạo đều export nó:
import { STORY_AGENT_ID } from './hooks/useAguiStoryAgent';Tùy chỉnh giao diện
Phần tiêu đề “Tùy chỉnh giao diện”<CopilotChat /> (và <CopilotSidebar />, <CopilotPopup />) sử dụng hệ thống slot đệ quy — bạn có thể ghi đè bất kỳ sub-component nào bằng chuỗi class Tailwind, object prop, hoặc component React tùy chỉnh. Xem hướng dẫn slots của CopilotKit để biết cây slot đầy đủ.
Theme tích hợp sẵn
Phần tiêu đề “Theme tích hợp sẵn”Generator đọc metadata.ux từ project trang web React của bạn và cung cấp một module wrapper có theme tại src/components/copilot/index.tsx để các component chat khớp với phần còn lại của UI của bạn mà không cần cấu hình thêm:
ux | Styling được áp dụng cho CopilotChat / CopilotSidebar / CopilotPopup |
|---|---|
cloudscape | Các tin nhắn được render bên trong Cloudscape ChatBubble với gen-AI Avatar (khớp với mẫu chat generative AI của Cloudscape); chỉ báo đang gõ trở thành LoadingBar và input là PromptInput. Được xây dựng từ @cloudscape-design/components và @cloudscape-design/chat-components. |
shadcn | Tin nhắn của assistant được render trong bubble bg-muted với avatar Sparkles; tin nhắn của người dùng được render căn phải trong bubble bg-primary với avatar User. Input là Textarea bo tròn + Button gửi/dừng hình viên thuốc (Enter để gửi, Shift+Enter để xuống dòng). Sử dụng các primitive shadcn từ package common-shadcn được chia sẻ. |
none (hoặc bất kỳ giá trị nào khác) | Không có theme — module chỉ re-export các component CopilotKit mặc định. |
Các component <AgentName>Chat được cung cấp đã có theme. Đối với một chat bạn tự kết nối, hãy import từ module theme cục bộ (không phải trực tiếp từ @copilotkit/react-core/v2) để theme được áp dụng tự động:
import { CopilotChat } from './components/copilot';import { STORY_AGENT_ID } from './hooks/useAguiStoryAgent';
<CopilotChat agentId={STORY_AGENT_ID} />Theme được áp dụng dưới dạng các slot mặc định, vì vậy bất kỳ slot nào bạn truyền một cách rõ ràng vẫn được ưu tiên — bạn vẫn giữ toàn quyền kiểm soát bất cứ khi nào bạn cần ghi đè một lần.
Tùy chỉnh Theme
Phần tiêu đề “Tùy chỉnh Theme”Theme được tạo nằm hoàn toàn bên trong project của bạn:
src/components/copilot/index.tsx— exportCopilotChat/CopilotSidebar/CopilotPopupcó theme và các objectcloudscapeCopilotTheme/shadcnCopilotTheme. Chỉnh sửa file này để thay đổi kết nối slot mặc định cho mọi chat trong ứng dụng của bạn.src/components/copilot/<ThemeComponent>.tsx— các component theme theo từng slot (ví dụ:CloudscapeAssistantMessage,ShadcnChatInput). Chỉnh sửa những file này để điều chỉnh giao diện của một slot duy nhất mà không cần kết nối lại theme.
Ví dụ: để thay thế renderer tin nhắn người dùng của riêng bạn trong khi vẫn giữ phần còn lại của theme, hãy chỉnh sửa file liên quan trong src/components/copilot/ và re-export nó từ index.tsx.
Styling Tailwind qua slots
Phần tiêu đề “Styling Tailwind qua slots”Các ghi đè theo từng chat vẫn hoạt động cùng với theme — bất kỳ thứ gì bạn truyền dưới dạng slot prop đều ghi đè mặc định có theme:
<StoryAgentChat // style the input and its children input={{ textArea: 'text-blue-600', sendButton: 'bg-blue-600 hover:bg-blue-700', }} // style nested message slots messageView={{ assistantMessage: 'bg-blue-50 rounded-xl p-2', userMessage: 'bg-blue-100 rounded-xl', }}/>Thay thế slot bằng component tùy chỉnh
Phần tiêu đề “Thay thế slot bằng component tùy chỉnh”Bất kỳ slot nào cũng có thể nhận một component React thay vì className, vì vậy bạn có thể thay thế hoàn toàn mặc định. Định kiểu component của bạn theo các props mà slot khai báo — sendButton render một <button>, vì vậy nó nhận ButtonHTMLAttributes:
import { StoryAgentChat } from './components/story-agent-chat';
const MySendButton: React.FC<React.ButtonHTMLAttributes<HTMLButtonElement>> = ({ onClick,}) => ( <button onClick={onClick} className="my-send-btn"> Send </button>);
<StoryAgentChat input={{ sendButton: MySendButton }} />;Các ghi đè sâu hơn tuân theo cùng một hình dạng — ví dụ: chỉ thay thế nút sao chép trên tin nhắn của assistant:
<StoryAgentChat messageView={{ assistantMessage: { copyButton: ({ onClick }) => <button onClick={onClick}>Copy</button>, }, }}/>Phát triển cục bộ
Phần tiêu đề “Phát triển cục bộ”Generator connection tự động cấu hình tích hợp dev:
- Chạy
nx dev <website>cũng sẽ khởi động server cục bộ của agent - Runtime config được ghi đè để trỏ đến URL AG-UI cục bộ (ví dụ:
http://localhost:8081) - Cả trang web và agent đều hot-reload cùng nhau
pnpm nx dev <WebsiteProject>yarn nx dev <WebsiteProject>npx nx dev <WebsiteProject>bunx nx dev <WebsiteProject>