Salta ai contenuti

React ad AG-UI Agent

Nx Plugin for AWS fornisce un generatore per connettere un sito web React a un Agent che espone il protocollo AG-UI. Collega CopilotKit con un HttpAgent @ag-ui/client sul tuo sito web, con supporto per l’autenticazione AWS IAM e Cognito.

Prima di utilizzare questo generatore, assicurati di avere:

  1. Un sito web React (generato utilizzando il generatore ts#website)
  2. Un Agent TypeScript o Python con protocol=ag-ui (generato utilizzando il generatore ts#agent o py#agent)
  3. Per gli agent distribuiti, Cognito Auth aggiunto tramite il generatore ts#website#auth

Esegui questo generatore@aws/nx-plugin:connection

pnpm nx g @aws/nx-plugin:connection
Componi il tuo comando5

Obbligatorio

Obbligatorio

Ti verrà richiesto di selezionare il tuo sito web React come progetto sorgente e il progetto contenente il tuo AG-UI Agent come progetto di destinazione. Se il tuo progetto di destinazione contiene più componenti (come più agent o altri tipi di componenti), ti verrà richiesto di specificare un targetComponent per disambiguare.

Opzioni del generatore5 opzioni
sourceProjectObbligatoriostring

Il progetto sorgente

targetProjectObbligatoriostring

Il progetto di destinazione a cui connettersi

sourceComponentstring

Il componente sorgente da cui connettersi (nome del componente, percorso relativo alla radice del progetto sorgente, o id del generatore). Usa '.' per selezionare esplicitamente il progetto come sorgente.

targetComponentstring

Il componente destinazione a cui connettersi (nome del componente, percorso relativo alla radice del progetto destinazione, o id del generatore). Usa '.' per selezionare esplicitamente il progetto come destinazione.

preferInstallDependenciesbooleanPredefinito: true

Se preferire l'installazione delle dipendenze dopo l'esecuzione del generatore. Impostare su false per rimandare l'installazione quando si eseguono più generatori in batch (l'installazione viene comunque eseguita se necessaria affinché i generatori successivi possano calcolare il grafo dei progetti Nx); installare una volta alla fine.

Il generatore crea un singolo componente condiviso AguiProvider, un hook per ogni agent connesso e un wrapper tematizzato per i componenti chat di CopilotKit:

  • Directorysrc
    • Directorycomponents
      • AguiProvider.tsx Singolo CopilotKitProvider per ogni agent AG-UI. Creato alla prima esecuzione di connection e aggiornato nelle esecuzioni successive per registrare ogni nuovo agent.
      • <agent-name>-chat.tsx Un <AgentName>Chat tematizzato associato all’id di questo agent. Un file per esecuzione di connection.
      • Directorycopilot
        • index.tsx Ri-esporta CopilotChat, CopilotSidebar e CopilotPopup con valori predefiniti per gli slot che corrispondono al ux del tuo sito web (Cloudscape, Shadcn, o nessun tema).
        • ThemeComponents .tsx Componenti tema per slot (ad es. CloudscapeAssistantMessage.tsx, ShadcnChatInput.tsx). Forniti solo quando ux è cloudscape o shadcn.
    • Directoryhooks
      • useAgui<AgentName>.tsx Registra un agent AG-UI ed esporta il suo id come <AGENT_NAME>_ID. Un file per esecuzione di connection.
      • useSigV4.tsx Firma SigV4 (solo IAM)

Eseguire connection una seconda volta per un agent diverso aggiunge un nuovo hook useAgui<AgentName>.tsx e componente <agent-name>-chat.tsx e aggiorna AguiProvider.tsx per registrare entrambi gli hook — eventuali modifiche personalizzate apportate al provider vengono preservate. main.tsx mantiene il suo singolo wrapper <AguiProvider> — non ti ritroverai mai con provider annidati.

Le seguenti dipendenze vengono aggiunte al package.json radice:

  • @copilotkit/react-core — fornisce CopilotKitProvider e componenti chat (CopilotChat, CopilotSidebar, CopilotPopup)
  • @ag-ui/clientHttpAgent utilizzato dagli hook generati
  • aws4fetch, oidc-client-ts, react-oidc-context, @aws-sdk/credential-providers — solo autenticazione IAM
  • react-oidc-context — autenticazione Cognito

Ogni hook useAgui<AgentName> legge il valore runtime del suo agent dalla Configurazione Runtime e istanzia un HttpAgent @ag-ui/client:

  • Distribuito: il valore runtime è un ARN Bedrock AgentCore Runtime, che viene convertito nell’endpoint HTTPS AgentCore: https://bedrock-agentcore.<region>.amazonaws.com/runtimes/<encoded-arn>/invocations?qualifier=DEFAULT
  • Sviluppo locale: dev sovrascrive il valore con l’URL locale dell’agent (ad es. http://localhost:8081)

L’AguiProvider condiviso chiama ogni hook generato e distribuisce ciascuno in selfManagedAgents su un singolo CopilotKitProvider, che li espone tutti ai componenti CopilotKit.

CopilotKit è il client React di riferimento di prima parte per il protocollo AG-UI e fornisce componenti chat pronti all’uso:

  • <CopilotChat /> — interfaccia chat completa
  • <CopilotSidebar /> — chat a pannello laterale fisso
  • <CopilotPopup /> — popup chat flottante

Posiziona uno qualsiasi di questi ovunque all’interno del wrapper <AguiProvider> (già collegato in main.tsx per te).

Il codice generato gestisce l’autenticazione in base alla configurazione del tuo agent:

  • IAM (predefinito): utilizza richieste HTTP firmate con AWS SigV4. Le credenziali vengono ottenute dal Cognito Identity Pool configurato con l’autenticazione del tuo sito web.
  • Cognito: incorpora il token di accesso JWT nell’header Authorization come Bearer token.

AG-UI e AgentCore Runtime identificano ciascuno una conversazione in modo diverso, e l’hook generato li collega insieme:

  • threadId — l’identificatore di conversazione AG-UI, inviato nel corpo della richiesta. CopilotKit genera un UUID casuale per chat a meno che non passi un threadId esplicito.
  • Session ID — la sessione AgentCore Runtime, inviata nell’header X-Amzn-Bedrock-AgentCore-Runtime-Session-Id. Seleziona la microVM che serve la richiesta, ed è ciò su cui il session.ts / session.py del tuo agent chiave lo stato della conversazione.

L’hook deriva il session ID dal thread ID, riempiendolo a destra fino ai 33 caratteri richiesti da AgentCore Runtime:

function agentCoreSessionId(input: RunAgentInput): string {
return (input.threadId ?? '').padEnd(33, '0');
}

Lasciare threadId non impostato è il modo più semplice — l’UUID generato da CopilotKit è già di 36 caratteri. Se ne passi uno esplicitamente, rendilo di almeno 33 caratteri, poiché il riempimento mappa thread ID che differiscono solo nei caratteri finali sulla stessa sessione.

Sia il Session ID che il Thread ID sono forniti dal browser. Per limitare ogni utente alle proprie conversazioni, fai riferimento alla guida py#agent o ts#agent.

Se il tuo agent utilizza l’autenticazione IAM, il ruolo autenticato del Cognito Identity Pool deve avere il permesso di invocare l’agent.

packages/infra/src/stacks/application-stack.ts
const identity = new UserIdentity(this, 'Identity');
const myAgent = new MyAgent(this, 'MyAgent');
// Grant the authenticated Cognito role permission to invoke the agent
myAgent.grantInvokeAccess(identity.identityPool.authenticatedRole);

grantInvokeAccess collega tutte le azioni di invocazione di AgentCore (InvokeAgentRuntime, InvokeAgentRuntimeWithWebSocketStream) sull’ARN di runtime dell’agent.

Se il tuo agent utilizza l’autenticazione Cognito, non è necessario definire alcuna infrastruttura aggiuntiva per connettere il tuo sito web al tuo agent.

Il generatore fornisce un componente <AgentName>Chat per ogni agent connesso, già associato all’id di quell’agent e tematizzato per corrispondere al ux del tuo sito web. Inseriscilo ovunque all’interno del 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...',
}}
/>
);
}

Inoltra ogni prop di CopilotChat tranne agentId, quindi tutto ciò che puoi passare a <CopilotChat /> funziona anche qui.

Esegui il generatore connection una volta per agent. Ogni esecuzione fornisce il componente chat proprio di quell’agent, quindi instradare una chat a un particolare agent è una questione di quale componente renderizzi:

import { StoryAgentChat } from './components/story-agent-chat';
import { ResearchAgentChat } from './components/research-agent-chat';
<StoryAgentChat /> {/* talks to StoryAgent */}
<ResearchAgentChat /> {/* talks to ResearchAgent */}

Se hai bisogno dell’id grezzo — per chiamare gli hook propri di CopilotKit, ad esempio — ogni hook generato lo esporta:

import { STORY_AGENT_ID } from './hooks/useAguiStoryAgent';

<CopilotChat /> (e <CopilotSidebar />, <CopilotPopup />) utilizzano un sistema di slot ricorsivo — puoi sovrascrivere qualsiasi sotto-componente con una stringa di classe Tailwind, un oggetto prop o un componente React personalizzato. Consulta la guida agli slot di CopilotKit per l’albero completo degli slot.

Il generatore legge metadata.ux dal tuo progetto sito web React e fornisce un modulo wrapper tematizzato in src/components/copilot/index.tsx in modo che i componenti chat corrispondano al resto della tua UI senza alcuna configurazione aggiuntiva:

uxStile applicato a CopilotChat / CopilotSidebar / CopilotPopup
cloudscapeI messaggi vengono renderizzati all’interno di ChatBubble Cloudscape con Avatar gen-AI (corrispondenti al pattern chat AI generativa Cloudscape); l’indicatore di digitazione diventa una LoadingBar e l’input è un PromptInput. Costruito da @cloudscape-design/components e @cloudscape-design/chat-components.
shadcnI messaggi dell’assistente vengono renderizzati in una bolla bg-muted con un avatar Sparkles; i messaggi utente vengono renderizzati allineati a destra in una bolla bg-primary con un avatar User. L’input è una Textarea arrotondata + Button di invio/stop a forma di pillola (Invio invia, Shift+Invio nuova riga). Utilizza primitive shadcn dal package condiviso common-shadcn.
none (o qualsiasi altro)Nessun tema — il modulo ri-esporta semplicemente i componenti CopilotKit predefiniti.

I componenti <AgentName>Chat forniti sono già tematizzati. Per una chat che colleghi tu stesso, importa dal modulo tema locale (non direttamente da @copilotkit/react-core/v2) in modo che il tema venga applicato automaticamente:

import { CopilotChat } from './components/copilot';
import { STORY_AGENT_ID } from './hooks/useAguiStoryAgent';
<CopilotChat agentId={STORY_AGENT_ID} />

Il tema viene applicato come valori predefiniti degli slot, quindi qualsiasi slot che passi esplicitamente ha comunque la precedenza — mantieni il pieno controllo ogni volta che hai bisogno di una sovrascrittura una tantum.

Il tema generato risiede interamente all’interno del tuo progetto:

  • src/components/copilot/index.tsx — esporta i CopilotChat / CopilotSidebar / CopilotPopup tematizzati e gli oggetti cloudscapeCopilotTheme / shadcnCopilotTheme. Modifica questo file per cambiare il collegamento predefinito degli slot per ogni chat nella tua app.
  • src/components/copilot/<ThemeComponent>.tsx — componenti tema per slot (ad es. CloudscapeAssistantMessage, ShadcnChatInput). Modificali per regolare l’aspetto di un singolo slot senza ricablare il tema.

Ad esempio, per inserire il tuo renderer di messaggi utente personalizzato mantenendo il resto del tema, modifica il file pertinente in src/components/copilot/ e ri-esportalo da index.tsx.

Le sovrascritture per chat funzionano ancora insieme al tema — qualsiasi cosa passi come prop slot sovrascrive il valore predefinito del tema:

<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',
}}
/>

Sostituire uno slot con un componente personalizzato

Sezione intitolata “Sostituire uno slot con un componente personalizzato”

Qualsiasi slot può accettare un componente React invece di un className, quindi puoi sostituire completamente il valore predefinito. Tipizza il tuo componente rispetto alle props che lo slot dichiara — sendButton renderizza un <button>, quindi riceve 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 }} />;

Le sovrascritture più profonde seguono la stessa forma — ad es. sostituisci solo il pulsante copia sui messaggi dell’assistente:

<StoryAgentChat
messageView={{
assistantMessage: {
copyButton: ({ onClick }) => <button onClick={onClick}>Copy</button>,
},
}}
/>

Il generatore di connessione configura automaticamente l’integrazione dev:

  1. Eseguire nx dev <website> avvierà anche il server locale dell’agent
  2. La configurazione runtime viene sovrascritta per puntare all’URL AG-UI locale (ad es. http://localhost:8081)
  3. Sia il sito web che l’agent si ricaricano automaticamente insieme
Terminal window
pnpm nx dev <WebsiteProject>