React vers Agent AG-UI
Nx Plugin for AWS fournit un générateur pour connecter un site web React à un Agent qui expose le protocole AG-UI. Il configure CopilotKit avec un HttpAgent @ag-ui/client sur votre site web, avec prise en charge de l’authentification AWS IAM et Cognito.
Prérequis
Section intitulée « Prérequis »Avant d’utiliser ce générateur, assurez-vous d’avoir :
- Un site web React (généré en utilisant le générateur
ts#website) - Un Agent TypeScript ou Python avec
protocol=ag-ui(généré en utilisant le générateurts#agentoupy#agent) - Pour les agents déployés, l’authentification Cognito ajoutée via le générateur
ts#website#auth
Utilisation
Section intitulée « Utilisation »Exécuter le générateur
Section intitulée « Exécuter le générateur »Exécuter ce générateur@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- Installez le Nx Console VSCode Plugin si ce n'est pas déjà fait
- Ouvrez la console Nx dans VSCode
- Cliquez sur
Generate (UI)dans la section "Common Nx Commands" - Recherchez
@aws/nx-plugin - connection - Remplissez les paramètres requis
- Cliquez sur
Generate
Composez votre commande5
Requis
Requis
Vous serez invité à sélectionner votre site web React comme projet source et le projet contenant votre Agent AG-UI comme projet cible. Si votre projet cible contient plusieurs composants (tels que plusieurs agents ou d’autres types de composants), vous serez invité à spécifier un targetComponent pour lever l’ambiguïté.
sourceProjectRequisstringLe projet source
targetProjectRequisstringLe projet cible auquel se connecter
sourceComponentstringLe composant source depuis lequel se connecter (nom du composant, chemin relatif à la racine du projet source, ou identifiant de générateur). Utilisez '.' pour sélectionner explicitement le projet comme source.
targetComponentstringLe composant cible auquel se connecter (nom du composant, chemin relatif à la racine du projet cible, ou identifiant de générateur). Utilisez '.' pour sélectionner explicitement le projet comme cible.
preferInstallDependenciesbooleanPar défaut:trueIndique s'il faut privilégier l'installation des dépendances après l'exécution du générateur. Définir à false pour différer l'installation lors de l'exécution de plusieurs générateurs en lot (une installation s'exécute quand même si nécessaire pour que les générateurs suivants puissent calculer le graphe de projet Nx) ; installer une seule fois à la fin.
Sortie du générateur
Section intitulée « Sortie du générateur »Le générateur crée un composant AguiProvider unique partagé, un hook par agent connecté, et un wrapper thématisé pour les composants de chat CopilotKit :
Répertoiresrc
Répertoirecomponents
- AguiProvider.tsx
CopilotKitProviderunique pour chaque agent AG-UI. Créé lors de la première exécution deconnectionet mis à jour lors des exécutions suivantes pour enregistrer chaque nouvel agent. - <agent-name>-chat.tsx Un
<AgentName>Chatthématisé lié à l’id de cet agent. Un fichier par exécution deconnection. Répertoirecopilot
- index.tsx Ré-exporte
CopilotChat,CopilotSidebaretCopilotPopupavec des valeurs par défaut de slot qui correspondent à l’uxde votre site web (Cloudscape, Shadcn, ou aucun thème). - ThemeComponents .tsx Composants de thème par slot (par ex.
CloudscapeAssistantMessage.tsx,ShadcnChatInput.tsx). Fournis uniquement lorsqueuxestcloudscapeoushadcn.
- index.tsx Ré-exporte
- AguiProvider.tsx
Répertoirehooks
- useAgui<AgentName>.tsx Enregistre un agent AG-UI et exporte son id en tant que
<AGENT_NAME>_ID. Un fichier par exécution deconnection. - useSigV4.tsx Signature SigV4 (IAM uniquement)
- useAgui<AgentName>.tsx Enregistre un agent AG-UI et exporte son id en tant que
Exécuter connection une deuxième fois pour un agent différent ajoute un nouveau hook useAgui<AgentName>.tsx et un composant <agent-name>-chat.tsx et met à jour AguiProvider.tsx pour enregistrer les deux hooks — toutes les modifications personnalisées que vous avez apportées au provider sont préservées. main.tsx conserve son unique wrapper <AguiProvider> — vous ne vous retrouvez jamais avec des providers imbriqués.
Les dépendances suivantes sont ajoutées au package.json racine :
@copilotkit/react-core— fournitCopilotKitProvideret les composants de chat (CopilotChat,CopilotSidebar,CopilotPopup)@ag-ui/client—HttpAgentutilisé par les hooks générésaws4fetch,oidc-client-ts,react-oidc-context,@aws-sdk/credential-providers— authentification IAM uniquementreact-oidc-context— authentification Cognito
Comment ça fonctionne
Section intitulée « Comment ça fonctionne »Connexion AG-UI
Section intitulée « Connexion AG-UI »Chaque hook useAgui<AgentName> lit la valeur d’exécution de son agent depuis la Configuration d’exécution et instancie un HttpAgent @ag-ui/client :
- Déployé : la valeur d’exécution est un ARN Bedrock AgentCore Runtime, qui est converti en point de terminaison HTTPS AgentCore :
https://bedrock-agentcore.<region>.amazonaws.com/runtimes/<encoded-arn>/invocations?qualifier=DEFAULT - Développement local :
devremplace la valeur par l’URL locale de l’agent (par ex.http://localhost:8081)
Le AguiProvider partagé appelle chaque hook généré et les étend tous dans selfManagedAgents sur un seul CopilotKitProvider, qui les expose tous aux composants CopilotKit.
Intégration CopilotKit
Section intitulée « Intégration CopilotKit »CopilotKit est le client React de référence officiel pour le protocole AG-UI et fournit des composants de chat prêts à l’emploi :
<CopilotChat />— interface de chat complète<CopilotSidebar />— chat en panneau latéral fixe<CopilotPopup />— popup de chat flottant
Placez n’importe lequel de ces composants n’importe où à l’intérieur du wrapper <AguiProvider> (déjà câblé dans main.tsx pour vous).
Authentification
Section intitulée « Authentification »Le code généré gère l’authentification en fonction de la configuration de votre agent :
- IAM (par défaut) : utilise des requêtes HTTP signées AWS SigV4. Les identifiants sont obtenus à partir du pool d’identités Cognito configuré avec l’authentification de votre site web.
- Cognito : intègre le jeton d’accès JWT dans l’en-tête
Authorizationen tant que jeton Bearer.
Sessions et Threads
Section intitulée « Sessions et Threads »AG-UI et AgentCore Runtime identifient chacun une conversation différemment, et le hook généré les relie ensemble :
threadId— l’identifiant de conversation AG-UI, envoyé dans le corps de la requête. CopilotKit génère un UUID aléatoire par chat sauf si vous passez unthreadIdexplicite.- Session ID — la session AgentCore Runtime, envoyée dans l’en-tête
X-Amzn-Bedrock-AgentCore-Runtime-Session-Id. Elle sélectionne la microVM qui traite la requête, et c’est ce sur quoi lesession.ts/session.pyde votre agent indexe l’état de la conversation.
Le hook dérive l’ID de session à partir de l’ID de thread, en le complétant à droite jusqu’aux 33 caractères requis par AgentCore Runtime :
function agentCoreSessionId(input: RunAgentInput): string { return (input.threadId ?? '').padEnd(33, '0');}Laisser threadId non défini est le plus simple — l’UUID généré par CopilotKit fait déjà 36 caractères. Si vous en passez un explicitement, assurez-vous qu’il fasse au moins 33 caractères, car le remplissage mappe les ID de thread qui ne diffèrent que par les caractères de fin sur la même session.
L’ID de session et l’ID de thread sont tous deux fournis par le navigateur. Pour restreindre chaque utilisateur à ses propres conversations, consultez le guide py#agent ou ts#agent.
Infrastructure
Section intitulée « Infrastructure »Si votre agent utilise l’authentification IAM, le rôle authentifié du pool d’identités Cognito doit recevoir l’autorisation d’invoquer l’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 configure toutes les actions d’invocation AgentCore (InvokeAgentRuntime, InvokeAgentRuntimeWithWebSocketStream) sur l’ARN d’exécution de l’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}Si votre agent utilise l’authentification Cognito, vous n’avez pas besoin de définir d’infrastructure supplémentaire pour connecter votre site web à votre agent.
Utilisation du code généré
Section intitulée « Utilisation du code généré »Ajout d’une interface de chat
Section intitulée « Ajout d’une interface de chat »Le générateur fournit un composant <AgentName>Chat par agent connecté, déjà lié à l’id de cet agent et thématisé pour correspondre à l’ux de votre site web. Placez-le n’importe où à l’intérieur du 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...', }} /> );}Il transmet toutes les props de CopilotChat sauf agentId, donc tout ce que vous pouvez passer à <CopilotChat /> fonctionne ici aussi.
Connexion de plusieurs agents AG-UI
Section intitulée « Connexion de plusieurs agents AG-UI »Exécutez le générateur connection une fois par agent. Chaque exécution fournit le composant de chat propre à cet agent, donc router un chat vers un agent particulier est une question de quel composant vous affichez :
import { StoryAgentChat } from './components/story-agent-chat';import { ResearchAgentChat } from './components/research-agent-chat';
<StoryAgentChat /> {/* talks to StoryAgent */}<ResearchAgentChat /> {/* talks to ResearchAgent */}Si vous avez besoin de l’id brut — pour appeler les propres hooks de CopilotKit, par exemple — chaque hook généré l’exporte :
import { STORY_AGENT_ID } from './hooks/useAguiStoryAgent';Personnalisation de l’apparence
Section intitulée « Personnalisation de l’apparence »<CopilotChat /> (et <CopilotSidebar />, <CopilotPopup />) utilisent un système de slots récursif — vous pouvez remplacer n’importe quel sous-composant par une chaîne de classe Tailwind, un objet de props, ou un composant React personnalisé. Consultez le guide des slots CopilotKit pour l’arborescence complète des slots.
Thèmes intégrés
Section intitulée « Thèmes intégrés »Le générateur lit metadata.ux depuis votre projet de site web React et fournit un module wrapper thématisé à src/components/copilot/index.tsx afin que les composants de chat correspondent au reste de votre interface utilisateur sans aucune configuration supplémentaire :
ux | Style appliqué à CopilotChat / CopilotSidebar / CopilotPopup |
|---|---|
cloudscape | Les messages s’affichent dans des ChatBubble Cloudscape avec des Avatar gen-AI (correspondant au modèle de chat IA générative Cloudscape) ; l’indicateur de saisie devient une LoadingBar et l’entrée est un PromptInput. Construit à partir de @cloudscape-design/components et @cloudscape-design/chat-components. |
shadcn | Les messages de l’assistant s’affichent dans une bulle bg-muted avec un avatar Sparkles ; les messages de l’utilisateur s’affichent alignés à droite dans une bulle bg-primary avec un avatar User. L’entrée est un Textarea arrondi + un Button d’envoi/arrêt en forme de pilule (Entrée soumet, Maj+Entrée nouvelle ligne). Utilise les primitives shadcn du package partagé common-shadcn. |
none (ou autre) | Pas de thème — le module ré-exporte simplement les composants CopilotKit par défaut. |
Les composants <AgentName>Chat fournis sont déjà thématisés. Pour un chat que vous câblez vous-même, importez depuis le module de thème local (pas directement depuis @copilotkit/react-core/v2) afin que le thème soit appliqué automatiquement :
import { CopilotChat } from './components/copilot';import { STORY_AGENT_ID } from './hooks/useAguiStoryAgent';
<CopilotChat agentId={STORY_AGENT_ID} />Le thème est appliqué en tant que valeurs par défaut de slot, donc tout slot que vous passez explicitement l’emporte toujours — vous gardez le contrôle total chaque fois que vous avez besoin d’un remplacement ponctuel.
Personnalisation du thème
Section intitulée « Personnalisation du thème »Le thème généré réside entièrement dans votre projet :
src/components/copilot/index.tsx— exporte lesCopilotChat/CopilotSidebar/CopilotPopupthématisés et les objetscloudscapeCopilotTheme/shadcnCopilotTheme. Modifiez ce fichier pour changer le câblage par défaut des slots pour chaque chat dans votre application.src/components/copilot/<ThemeComponent>.tsx— composants de thème par slot (par ex.CloudscapeAssistantMessage,ShadcnChatInput). Modifiez-les pour ajuster l’apparence d’un seul slot sans recâbler le thème.
Par exemple, pour intégrer votre propre rendu de message utilisateur tout en conservant le reste du thème, modifiez le fichier pertinent dans src/components/copilot/ et ré-exportez-le depuis index.tsx.
Style Tailwind via les slots
Section intitulée « Style Tailwind via les slots »Les remplacements par chat fonctionnent toujours avec le thème — tout ce que vous passez comme prop de slot remplace la valeur par défaut du thème :
<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', }}/>Remplacement d’un slot par un composant personnalisé
Section intitulée « Remplacement d’un slot par un composant personnalisé »N’importe quel slot peut prendre un composant React au lieu d’un className, vous pouvez donc remplacer complètement la valeur par défaut. Typez votre composant en fonction des props que le slot déclare — sendButton rend un <button>, il reçoit donc 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 }} />;Les remplacements plus profonds suivent la même structure — par ex. remplacer uniquement le bouton de copie sur les messages de l’assistant :
<StoryAgentChat messageView={{ assistantMessage: { copyButton: ({ onClick }) => <button onClick={onClick}>Copy</button>, }, }}/>Développement local
Section intitulée « Développement local »Le générateur de connexion configure automatiquement l’intégration dev :
- L’exécution de
nx dev <website>démarrera également le serveur local de l’agent - La configuration d’exécution est remplacée pour pointer vers l’URL AG-UI locale (par ex.
http://localhost:8081) - Le site web et l’agent se rechargent à chaud ensemble
pnpm nx dev <WebsiteProject>yarn nx dev <WebsiteProject>npx nx dev <WebsiteProject>bunx nx dev <WebsiteProject>