React to AG-UI Agent
Nx Plugin for AWS provides a generator to connect a React website to a Strands Agent that exposes the AG-UI protocol. It wires up CopilotKit with an @ag-ui/client HttpAgent on your website, with AWS IAM and Cognito authentication support.
Prerequisites
Section titled “Prerequisites”Before using this generator, ensure you have:
- A React website (generated using the
ts#react-websitegenerator) - A Python Strands Agent with
protocol=AG-UI(generated using thepy#strands-agentgenerator) - For deployed agents, Cognito Auth added via the
ts#react-website-authgenerator
Run the Generator
Section titled “Run the Generator”- Install the Nx Console VSCode Plugin if you haven't already
- Open the Nx Console in VSCode
- Click
Generate (UI)in the "Common Nx Commands" section - Search for
@aws/nx-plugin - connection - Fill in the required parameters
- Click
Generate
pnpm nx g @aws/nx-plugin:connectionyarn nx g @aws/nx-plugin:connectionnpx nx g @aws/nx-plugin:connectionbunx nx g @aws/nx-plugin:connectionYou can also perform a dry-run to see what files would be changed
pnpm nx g @aws/nx-plugin:connection --dry-runyarn nx g @aws/nx-plugin:connection --dry-runnpx nx g @aws/nx-plugin:connection --dry-runbunx nx g @aws/nx-plugin:connection --dry-runYou will be prompted to select your React website as the source project and the project containing your AG-UI Strands Agent as the target project. If your target project contains multiple components (such as multiple agents or other component types), you will be prompted to specify a targetComponent to disambiguate.
Options
Section titled “Options”| Parameter | Type | Default | Description |
|---|---|---|---|
| sourceProject Required | string | - | The source project |
| targetProject Required | string | - | The target project to connect to |
| sourceComponent | string | - | The source component to connect from (component name, path relative to source project root, or generator id). Use '.' to explicitly select the project as the source. |
| targetComponent | string | - | The target component to connect to (component name, path relative to target project root, or generator id). Use '.' to explicitly select the project as the target. |
Generator Output
Section titled “Generator Output”The generator creates a single shared AguiProvider component, one hook per connected agent, and a themed wrapper for the CopilotKit chat components:
Directorysrc
Directorycomponents
- AguiProvider.tsx Single
CopilotKitProviderfor every AG-UI agent. Created on the firstconnectionrun and updated on subsequent runs to register each new agent. Directorycopilot
- index.tsx Re-exports
CopilotChat,CopilotSidebarandCopilotPopupwith slot defaults that match your website’suxProvider(Cloudscape, Shadcn, or no theme at all). - ThemeComponents .tsx Per-slot theme components (e.g.
CloudscapeAssistantMessage.tsx,ShadcnChatInput.tsx). Only vended whenuxProviderisCloudscapeorShadcn.
- index.tsx Re-exports
- AguiProvider.tsx Single
Directoryhooks
- useAgui<AgentName>.tsx Registers one AG-UI agent. One file per
connectionrun. - useSigV4.tsx SigV4 signing (IAM only)
- useAgui<AgentName>.tsx Registers one AG-UI agent. One file per
Running connection a second time for a different agent adds a new useAgui<AgentName>.tsx hook and updates AguiProvider.tsx to register both hooks — any custom edits you’ve made to the provider are preserved. main.tsx keeps its single <AguiProvider> wrapper — you never end up with nested providers.
The following dependencies are added to the root package.json:
@copilotkit/react-core— shipsCopilotKitProviderand chat components (CopilotChat,CopilotSidebar,CopilotPopup)@ag-ui/client—HttpAgentused by the generated hooksaws4fetch,oidc-client-ts,react-oidc-context,@aws-sdk/credential-providers— IAM auth onlyreact-oidc-context— Cognito auth
How It Works
Section titled “How It Works”AG-UI Connection
Section titled “AG-UI Connection”Each useAgui<AgentName> hook reads its agent’s runtime value from Runtime Configuration and instantiates an @ag-ui/client HttpAgent:
- Deployed: the runtime value is a Bedrock AgentCore Runtime ARN, which is converted to the AgentCore HTTPS endpoint:
https://bedrock-agentcore.<region>.amazonaws.com/runtimes/<encoded-arn>/invocations?qualifier=DEFAULT - Local development:
serve-localoverrides the value to the agent’s local URL (e.g.http://localhost:8081)
The shared AguiProvider calls every generated hook and spreads each one into selfManagedAgents on a single CopilotKitProvider, which exposes them all to CopilotKit components.
CopilotKit Integration
Section titled “CopilotKit Integration”CopilotKit is the 1st-party reference React client for the AG-UI protocol and ships ready-made chat components:
<CopilotChat />— full chat interface<CopilotSidebar />— fixed side panel chat<CopilotPopup />— floating chat popup
Place any of these anywhere inside the <AguiProvider> wrapper (already wired into main.tsx for you).
Authentication
Section titled “Authentication”The generated code handles authentication depending on your agent’s configuration:
- IAM (default): uses AWS SigV4-signed HTTP requests. Credentials are obtained from the Cognito Identity Pool configured with your website’s auth.
- Cognito: embeds the JWT access token in the
Authorizationheader as a Bearer token.
Infrastructure
Section titled “Infrastructure”If your agent uses IAM auth, the Cognito Identity Pool’s authenticated role must be granted permission to invoke the 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 wires up all AgentCore invoke actions (InvokeAgentRuntime, InvokeAgentRuntimeWithWebSocketStream) on the agent’s runtime ARN.
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}If your agent uses Cognito auth, you do not need to define any additional infrastructure to connect your website to your agent.
Using the Generated Code
Section titled “Using the Generated Code”Adding a Chat Interface
Section titled “Adding a Chat Interface”Instantiate CopilotKit components with agentId to select which agent to use. The id is the agent’s name — the same one you chose when you ran the py#strands-agent generator — and you can also find it in the generated hook file (e.g. the key returned from packages/web/src/hooks/useAgui<AgentName>.tsx).
Import the chat components from the generated ./components/copilot module so the theme that matches your website’s uxProvider is applied automatically:
import { CopilotChat } from './components/copilot';
function ChatPage() { return ( <CopilotChat agentId="agent" labels={{ welcomeMessageText: 'How can I help you today?', chatInputPlaceholder: 'Ask me anything...', }} /> );}Connecting Multiple AG-UI Agents
Section titled “Connecting Multiple AG-UI Agents”Run the connection generator once per agent. Every agent registered via the shared AguiProvider is visible from anywhere in the app — instantiate a CopilotKit component with a different agentId to route each chat to the agent you want:
import { CopilotChat } from './components/copilot';
<CopilotChat agentId="story" /> {/* talks to StoryAgent */}<CopilotChat agentId="research" /> {/* talks to ResearchAgent */}Customising the Look and Feel
Section titled “Customising the Look and Feel”<CopilotChat /> (and <CopilotSidebar />, <CopilotPopup />) use a recursive slot system — you can override any sub-component with either a Tailwind class string, a prop object, or a custom React component. See the CopilotKit slots guide for the full slot tree.
Built-in Themes
Section titled “Built-in Themes”The generator reads metadata.uxProvider from your React website project and vends a themed wrapper module at src/components/copilot/index.tsx so the chat components match the rest of your UI without any extra configuration:
uxProvider | Styling applied to CopilotChat / CopilotSidebar / CopilotPopup |
|---|---|
Cloudscape | Messages render inside Cloudscape ChatBubbles with gen-AI Avatars (matching the Cloudscape generative AI chat pattern); the typing indicator becomes a LoadingBar and the input is a PromptInput. Built from @cloudscape-design/components and @cloudscape-design/chat-components. |
Shadcn | Assistant messages render in a bg-muted bubble with a Sparkles avatar; user messages render right-aligned in a bg-primary bubble with a User avatar. The input is a rounded Textarea + pill-shaped send/stop Button (Enter submits, Shift+Enter newlines). Uses shadcn primitives from the shared common-shadcn package. |
None (or anything else) | No theme — the module just re-exports the default CopilotKit components. |
Import the themed components from the local theme module (not @copilotkit/react-core/v2 directly) so the theme is applied automatically:
import { CopilotChat } from './components/copilot';
<CopilotChat agentId="agent" />The theme is applied as slot defaults, so any slot you explicitly pass still wins — you keep full control whenever you need a one-off override.
Customising the Theme
Section titled “Customising the Theme”The generated theme lives entirely inside your project:
src/components/copilot/index.tsx— exports the themedCopilotChat/CopilotSidebar/CopilotPopupand thecloudscapeCopilotTheme/shadcnCopilotThemeobjects. Edit this file to change the default slot wiring for every chat in your app.src/components/copilot/<ThemeComponent>.tsx— per-slot theme components (e.g.CloudscapeAssistantMessage,ShadcnChatInput). Edit these to tweak the look of a single slot without re-wiring the theme.
For example, to drop in your own user-message renderer while keeping the rest of the theme, edit the relevant file in src/components/copilot/ and re-export it from index.tsx.
Tailwind styling via slots
Section titled “Tailwind styling via slots”Per-chat overrides still work alongside the theme — anything you pass as a slot prop overrides the themed default:
<CopilotChat agentId="agent" // 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', }}/>Replacing a slot with a custom component
Section titled “Replacing a slot with a custom component”Any slot can take a React component instead of a className, so you can replace the default entirely:
import { CopilotChat } from './components/copilot';
const MySendButton: React.FC<{ onClick: () => void }> = ({ onClick }) => ( <button onClick={onClick} className="my-send-btn"> Send </button>);
<CopilotChat agentId="agent" input={{ sendButton: MySendButton }}/>;Deeper overrides follow the same shape — e.g. replace just the copy button on assistant messages:
<CopilotChat agentId="agent" messageView={{ assistantMessage: { copyButton: ({ onClick }) => <button onClick={onClick}>Copy</button>, }, }}/>Local Development
Section titled “Local Development”The connection generator automatically configures serve-local integration:
- Running
nx serve-local <website>will also start the agent’s local server - The runtime config is overridden to point to the local AG-UI URL (e.g.
http://localhost:8081) - Both the website and the agent hot-reload together
pnpm nx serve-local <WebsiteProject>yarn nx serve-local <WebsiteProject>npx nx serve-local <WebsiteProject>bunx nx serve-local <WebsiteProject>