Skip to content

React から AG-UI Agent へ

Nx Plugin for AWS は、AG-UI プロトコルを公開する Agent に React ウェブサイトを接続するためのジェネレーターを提供します。これは、AWS IAM および Cognito 認証サポートを備えた @ag-ui/client HttpAgent を使用して、ウェブサイト上で CopilotKit を配線します。

このジェネレーターを使用する前に、以下を確認してください:

  1. React ウェブサイト(ts#website ジェネレーターを使用して生成)
  2. protocol=ag-ui を持つ TypeScript または Python Agent(ts#agent または py#agent ジェネレーターを使用して生成)
  3. デプロイされた Agent の場合、ts#website#auth ジェネレーター経由で追加された Cognito Auth
Terminal window
pnpm nx g @aws/nx-plugin:connection
変更されるファイルを確認するためにドライランを実行することもできます
Terminal window
pnpm nx g @aws/nx-plugin:connection --dry-run

React ウェブサイトをソースプロジェクトとして、AG-UI Agent を含むプロジェクトをターゲットプロジェクトとして選択するよう求められます。ターゲットプロジェクトに複数のコンポーネント(複数の Agent や他のコンポーネントタイプなど)が含まれている場合は、曖昧さを解消するために targetComponent を指定するよう求められます。

パラメータデフォルト説明
sourceProject 必須string-ソース プロジェクト
targetProject 必須string-接続先のターゲット プロジェクト
sourceComponent string-接続元のソース コンポーネント (コンポーネント名、ソース プロジェクト ルートからの相対パス、またはジェネレーター ID)。プロジェクトをソースとして明示的に選択するには '.' を使用します。
targetComponent string-接続先のターゲット コンポーネント (コンポーネント名、ターゲット プロジェクト ルートからの相対パス、またはジェネレーター ID)。プロジェクトをターゲットとして明示的に選択するには '.' を使用します。
preferInstallDependencies booleantrueジェネレーター実行後に依存関係のインストールを優先するかどうか。複数のジェネレーターをバッチ処理する際にインストールを延期する場合はfalseに設定します(後続のジェネレーターがNxプロジェクトグラフを計算できるよう、必要に応じてインストールは実行されます)。最後に一度だけインストールします。

ジェネレーターは、単一の共有 AguiProvider コンポーネント、接続された Agent ごとに 1 つのフック、および CopilotKit チャットコンポーネント用のテーマ付きラッパーを作成します:

  • Directorysrc
    • Directorycomponents
      • AguiProvider.tsx すべての AG-UI Agent 用の単一の CopilotKitProvider。最初の connection 実行時に作成され、後続の実行で各新しい Agent を登録するために更新されます。
      • Directorycopilot
        • index.tsx ウェブサイトの ux(Cloudscape、Shadcn、またはテーマなし)に一致するスロットデフォルトを持つ CopilotChatCopilotSidebarCopilotPopup を再エクスポートします。
        • ThemeComponents .tsx スロットごとのテーマコンポーネント(例:CloudscapeAssistantMessage.tsxShadcnChatInput.tsx)。uxcloudscape または shadcn の場合のみ提供されます。
    • Directoryhooks
      • useAgui<AgentName>.tsx 1 つの AG-UI Agent を登録します。connection 実行ごとに 1 つのファイル。
      • useSigV4.tsx SigV4 署名(IAM のみ)

異なる Agent に対して 2 回目の connection を実行すると、新しい useAgui<AgentName>.tsx フックが追加され、AguiProvider.tsx が更新されて両方のフックが登録されます — プロバイダーに加えたカスタム編集は保持されます。main.tsx は単一の <AguiProvider> ラッパーを保持します — ネストされたプロバイダーになることはありません。

以下の依存関係がルートの package.json に追加されます:

  • @copilotkit/react-coreCopilotKitProvider とチャットコンポーネント(CopilotChatCopilotSidebarCopilotPopup)を提供
  • @ag-ui/client — 生成されたフックで使用される HttpAgent
  • aws4fetchoidc-client-tsreact-oidc-context@aws-sdk/credential-providers — IAM 認証のみ
  • react-oidc-context — Cognito 認証

useAgui<AgentName> フックは、ランタイム設定から Agent のランタイム値を読み取り、@ag-ui/client HttpAgent をインスタンス化します:

  • デプロイ済み:ランタイム値は Bedrock AgentCore Runtime ARN であり、AgentCore HTTPS エンドポイントに変換されます:https://bedrock-agentcore.<region>.amazonaws.com/runtimes/<encoded-arn>/invocations?qualifier=DEFAULT
  • ローカル開発dev は値を Agent のローカル URL(例:http://localhost:8081)にオーバーライドします

共有 AguiProvider はすべての生成されたフックを呼び出し、それぞれを単一の CopilotKitProviderselfManagedAgents に展開し、すべてを CopilotKit コンポーネントに公開します。

CopilotKit は AG-UI プロトコル用の第一級の参照 React クライアントであり、すぐに使えるチャットコンポーネントを提供します:

  • <CopilotChat /> — 完全なチャットインターフェース
  • <CopilotSidebar /> — 固定サイドパネルチャット
  • <CopilotPopup /> — フローティングチャットポップアップ

これらのいずれかを <AguiProvider> ラッパー内の任意の場所に配置します(すでに main.tsx に配線されています)。

生成されたコードは、Agent の設定に応じて認証を処理します:

  • IAM(デフォルト):AWS SigV4 署名付き HTTP リクエストを使用します。認証情報は、ウェブサイトの認証で設定された Cognito Identity Pool から取得されます。
  • Cognito:JWT アクセストークンを Bearer トークンとして Authorization ヘッダーに埋め込みます。

AG-UI と AgentCore Runtime はそれぞれ異なる方法で会話を識別し、生成されたフックがそれらを結び付けます:

  • threadId — AG-UI の会話識別子で、リクエストボディで送信されます。CopilotKit は、明示的な threadId を渡さない限り、チャットごとにランダムな UUID を生成します。
  • Session ID — AgentCore Runtime のセッションで、X-Amzn-Bedrock-AgentCore-Runtime-Session-Id ヘッダーで送信されます。これはリクエストを処理する microVM を選択し、Agent の session.ts / session.py が会話状態をキーとするものです。

フックは、スレッド ID からセッション ID を導出し、AgentCore Runtime が必要とする 33 文字に右パディングします:

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

threadId を未設定のままにするのが最も簡単です — CopilotKit が生成する UUID はすでに 36 文字です。明示的に渡す場合は、少なくとも 33 文字にしてください。パディングにより、末尾の文字のみが異なるスレッド ID が同じセッションにマッピングされるためです。

Session ID と Thread ID の両方はブラウザーによって提供されます。各ユーザーを自分の会話に制限するには、py#agent または ts#agent ガイドを参照してください。

エージェントが IAM 認証を使用する場合、Cognito Identity Pool の認証済みロールにエージェントを呼び出す権限を付与する必要があります。

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 は、エージェントのランタイム ARN 上のすべての AgentCore 呼び出しアクション(InvokeAgentRuntimeInvokeAgentRuntimeWithWebSocketStream)を接続します。

エージェントが Cognito 認証を使用する場合、ウェブサイトをエージェントに接続するための追加のインフラストラクチャを定義する必要はありません。

チャットインターフェースの追加

Section titled “チャットインターフェースの追加”

使用する Agent を選択するために agentId を指定して CopilotKit コンポーネントをインスタンス化します。id は Agent の名前です — ts#agent または py#agent ジェネレーターを実行したときに選択したものと同じです — また、生成されたフックファイル(例:packages/web/src/hooks/useAgui<AgentName>.tsx から返されるキー)でも確認できます。

ウェブサイトの ux に一致するテーマが自動的に適用されるように、生成された ./components/copilot モジュールからチャットコンポーネントをインポートします:

import { CopilotChat } from './components/copilot';
function ChatPage() {
return (
<CopilotChat
agentId="agent"
labels={{
welcomeMessageText: 'How can I help you today?',
chatInputPlaceholder: 'Ask me anything...',
}}
/>
);
}

Agent ごとに 1 回 connection ジェネレーターを実行します。共有 AguiProvider 経由で登録されたすべての Agent は、アプリ内のどこからでも表示されます — 異なる agentId を持つ CopilotKit コンポーネントをインスタンス化して、各チャットを目的の Agent にルーティングします:

import { CopilotChat } from './components/copilot';
<CopilotChat agentId="story" /> {/* talks to StoryAgent */}
<CopilotChat agentId="research" /> {/* talks to ResearchAgent */}

ルック&フィールのカスタマイズ

Section titled “ルック&フィールのカスタマイズ”

<CopilotChat />(および <CopilotSidebar /><CopilotPopup />)は再帰的なスロットシステムを使用します — 任意のサブコンポーネントを Tailwind クラス文字列、プロップオブジェクト、またはカスタム React コンポーネントでオーバーライドできます。完全なスロットツリーについては、CopilotKit スロットガイドを参照してください。

ジェネレーターは React ウェブサイトプロジェクトから metadata.ux を読み取り、src/components/copilot/index.tsx にテーマ付きラッパーモジュールを提供するため、追加の設定なしでチャットコンポーネントが UI の残りの部分と一致します:

uxCopilotChat / CopilotSidebar / CopilotPopup に適用されるスタイリング
cloudscapeメッセージは Cloudscape ChatBubble 内に gen-AI Avatar とともにレンダリングされます(Cloudscape 生成 AI チャットパターンに一致);タイピングインジケーターは LoadingBar になり、入力は PromptInput になります。@cloudscape-design/components@cloudscape-design/chat-components から構築されます。
shadcnアシスタントメッセージは bg-muted バブル内に Sparkles アバターとともにレンダリングされます;ユーザーメッセージは bg-primary バブル内に User アバターとともに右揃えでレンダリングされます。入力は丸みを帯びた Textarea + ピル型の送信/停止 Button です(Enter で送信、Shift+Enter で改行)。共有 common-shadcn パッケージの shadcn プリミティブを使用します。
none(またはその他)テーマなし — モジュールはデフォルトの CopilotKit コンポーネントを再エクスポートするだけです。

テーマが自動的に適用されるように、ローカルテーマモジュールからテーマ付きコンポーネントをインポートします(@copilotkit/react-core/v2 から直接ではなく):

import { CopilotChat } from './components/copilot';
<CopilotChat agentId="agent" />

テーマはスロットデフォルトとして適用されるため、明示的に渡すスロットは引き続き優先されます — 一回限りのオーバーライドが必要な場合でも、完全な制御を維持できます。

生成されたテーマは完全にプロジェクト内に存在します:

  • src/components/copilot/index.tsx — テーマ付き CopilotChat / CopilotSidebar / CopilotPopupcloudscapeCopilotTheme / shadcnCopilotTheme オブジェクトをエクスポートします。このファイルを編集して、アプリ内のすべてのチャットのデフォルトスロット配線を変更します。
  • src/components/copilot/<ThemeComponent>.tsx — スロットごとのテーマコンポーネント(例:CloudscapeAssistantMessageShadcnChatInput)。テーマを再配線せずに単一のスロットの外観を調整するには、これらを編集します。

たとえば、テーマの残りの部分を維持しながら独自のユーザーメッセージレンダラーをドロップインするには、src/components/copilot/ 内の関連ファイルを編集し、index.tsx から再エクスポートします。

スロット経由の Tailwind スタイリング

Section titled “スロット経由の Tailwind スタイリング”

チャットごとのオーバーライドは、テーマと並行して機能します — スロットプロップとして渡すものは、テーマのデフォルトをオーバーライドします:

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

カスタムコンポーネントでスロットを置き換える

Section titled “カスタムコンポーネントでスロットを置き換える”

任意のスロットは className の代わりに React コンポーネントを取ることができるため、デフォルトを完全に置き換えることができます:

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 }}
/>;

より深いオーバーライドも同じ形状に従います — 例えば、アシスタントメッセージのコピーボタンだけを置き換える:

<CopilotChat
agentId="agent"
messageView={{
assistantMessage: {
copyButton: ({ onClick }) => <button onClick={onClick}>Copy</button>,
},
}}
/>

接続ジェネレーターは自動的に dev 統合を設定します:

  1. nx dev <website> を実行すると、Agent のローカルサーバーも起動します
  2. ランタイム設定はローカル AG-UI URL(例:http://localhost:8081)を指すようにオーバーライドされます
  3. ウェブサイトと Agent の両方が一緒にホットリロードされます
Terminal window
pnpm nx dev <WebsiteProject>