콘텐츠로 이동

React에서 AG-UI Agent로

Nx Plugin for AWS는 AG-UI 프로토콜을 노출하는 Agent에 React 웹사이트를 연결하는 생성기를 제공합니다. 이는 웹사이트에서 @ag-ui/client HttpAgent와 함께 CopilotKit을 연결하며, AWS IAM 및 Cognito 인증을 지원합니다.

이 생성기를 사용하기 전에 다음이 필요합니다:

  1. React 웹사이트 (ts#website 생성기를 사용하여 생성)
  2. protocol=ag-ui를 사용하는 TypeScript 또는 Python Agent (ts#agent 또는 py#agent 생성기를 사용하여 생성)
  3. 배포된 에이전트의 경우, 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가 포함된 프로젝트를 선택하라는 메시지가 표시됩니다. 타겟 프로젝트에 여러 컴포넌트(여러 에이전트 또는 다른 컴포넌트 유형)가 포함된 경우, 명확히 구분하기 위해 targetComponent를 지정하라는 메시지가 표시됩니다.

매개변수타입기본값설명
sourceProject 필수string-소스 프로젝트
targetProject 필수string-연결할 대상 프로젝트
sourceComponent string-연결을 시작할 소스 컴포넌트 (컴포넌트 이름, 소스 프로젝트 루트 기준 상대 경로, 또는 generator id). 프로젝트를 소스로 명시적으로 선택하려면 '.'을 사용하세요.
targetComponent string-연결할 대상 컴포넌트 (컴포넌트 이름, 대상 프로젝트 루트 기준 상대 경로, 또는 generator id). 프로젝트를 대상으로 명시적으로 선택하려면 '.'을 사용하세요.
preferInstallDependencies booleantrue생성기 실행 후 의존성 설치를 선호할지 여부입니다. 여러 생성기를 일괄 처리할 때 설치를 연기하려면 false로 설정하세요 (후속 생성기가 Nx 프로젝트 그래프를 계산할 수 있도록 필요한 경우 설치는 여전히 실행됩니다); 마지막에 한 번만 설치합니다.

생성기는 단일 공유 AguiProvider 컴포넌트, 연결된 에이전트당 하나의 훅, 그리고 CopilotKit 채팅 컴포넌트를 위한 테마 래퍼를 생성합니다:

  • 디렉터리src
    • 디렉터리components
      • AguiProvider.tsx 모든 AG-UI 에이전트를 위한 단일 CopilotKitProvider. 첫 번째 connection 실행 시 생성되고 후속 실행 시 각 새 에이전트를 등록하도록 업데이트됩니다.
      • 디렉터리copilot
        • index.tsx 웹사이트의 ux(Cloudscape, Shadcn 또는 테마 없음)와 일치하는 슬롯 기본값으로 CopilotChat, CopilotSidebarCopilotPopup을 재내보냅니다.
        • ThemeComponents .tsx 슬롯별 테마 컴포넌트(예: CloudscapeAssistantMessage.tsx, ShadcnChatInput.tsx). uxcloudscape 또는 shadcn일 때만 제공됩니다.
    • 디렉터리hooks
      • useAgui<AgentName>.tsx 하나의 AG-UI 에이전트를 등록합니다. connection 실행당 하나의 파일.
      • useSigV4.tsx SigV4 서명 (IAM 전용)

다른 에이전트에 대해 두 번째로 connection을 실행하면 새로운 useAgui<AgentName>.tsx 훅이 추가되고 AguiProvider.tsx가 두 훅을 모두 등록하도록 업데이트됩니다 — 프로바이더에 대한 사용자 정의 편집 내용은 보존됩니다. main.tsx는 단일 <AguiProvider> 래퍼를 유지하므로 중첩된 프로바이더가 생기지 않습니다.

다음 종속성이 루트 package.json에 추가됩니다:

  • @copilotkit/react-coreCopilotKitProvider 및 채팅 컴포넌트(CopilotChat, CopilotSidebar, CopilotPopup)를 제공합니다
  • @ag-ui/client — 생성된 훅에서 사용하는 HttpAgent
  • aws4fetch, oidc-client-ts, react-oidc-context, @aws-sdk/credential-providers — IAM 인증 전용
  • react-oidc-context — Cognito 인증

useAgui<AgentName> 훅은 런타임 구성에서 에이전트의 런타임 값을 읽고 @ag-ui/client HttpAgent를 인스턴스화합니다:

  • 배포됨: 런타임 값은 Bedrock AgentCore Runtime ARN이며, 이는 AgentCore HTTPS 엔드포인트로 변환됩니다: https://bedrock-agentcore.<region>.amazonaws.com/runtimes/<encoded-arn>/invocations?qualifier=DEFAULT
  • 로컬 개발: dev가 값을 에이전트의 로컬 URL(예: http://localhost:8081)로 재정의합니다

공유 AguiProvider는 생성된 모든 훅을 호출하고 각각을 단일 CopilotKitProviderselfManagedAgents에 펼쳐서 CopilotKit 컴포넌트에 모두 노출합니다.

CopilotKit은 AG-UI 프로토콜을 위한 1st-party 참조 React 클라이언트이며 즉시 사용 가능한 채팅 컴포넌트를 제공합니다:

  • <CopilotChat /> — 전체 채팅 인터페이스
  • <CopilotSidebar /> — 고정 사이드 패널 채팅
  • <CopilotPopup /> — 플로팅 채팅 팝업

이들 중 하나를 <AguiProvider> 래퍼 내부 어디에나 배치할 수 있습니다(이미 main.tsx에 연결되어 있습니다).

생성된 코드는 에이전트의 구성에 따라 인증을 처리합니다:

  • 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을 선택하며, 에이전트의 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 호출 작업(InvokeAgentRuntime, InvokeAgentRuntimeWithWebSocketStream)을 연결합니다.

에이전트가 Cognito 인증을 사용하는 경우, 웹사이트를 에이전트에 연결하기 위해 추가 인프라를 정의할 필요가 없습니다.

사용할 에이전트를 선택하려면 agentId와 함께 CopilotKit 컴포넌트를 인스턴스화합니다. id는 에이전트의 이름입니다 — 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...',
}}
/>
);
}

에이전트당 한 번씩 connection 생성기를 실행합니다. 공유 AguiProvider를 통해 등록된 모든 에이전트는 앱의 어디에서나 볼 수 있습니다 — 각 채팅을 원하는 에이전트로 라우팅하려면 다른 agentId로 CopilotKit 컴포넌트를 인스턴스화합니다:

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

<CopilotChat /> (및 <CopilotSidebar />, <CopilotPopup />)는 재귀적 슬롯 시스템을 사용합니다 — Tailwind 클래스 문자열, prop 객체 또는 사용자 정의 React 컴포넌트로 모든 하위 컴포넌트를 재정의할 수 있습니다. 전체 슬롯 트리는 CopilotKit 슬롯 가이드를 참조하세요.

생성기는 React 웹사이트 프로젝트에서 metadata.ux를 읽고 src/components/copilot/index.tsx에 테마 래퍼 모듈을 제공하여 추가 구성 없이 채팅 컴포넌트가 나머지 UI와 일치하도록 합니다:

uxCopilotChat / CopilotSidebar / CopilotPopup에 적용되는 스타일
cloudscape메시지는 gen-AI Avatar가 있는 Cloudscape ChatBubble 내부에 렌더링됩니다(Cloudscape 생성형 AI 채팅 패턴과 일치); 타이핑 표시기는 LoadingBar가 되고 입력은 PromptInput입니다. @cloudscape-design/components@cloudscape-design/chat-components로 구축됩니다.
shadcn어시스턴트 메시지는 Sparkles 아바타가 있는 bg-muted 버블에 렌더링됩니다; 사용자 메시지는 User 아바타가 있는 bg-primary 버블에 오른쪽 정렬로 렌더링됩니다. 입력은 둥근 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 — 슬롯별 테마 컴포넌트(예: CloudscapeAssistantMessage, ShadcnChatInput). 테마를 다시 연결하지 않고 단일 슬롯의 모양을 조정하려면 이를 편집합니다.

예를 들어, 테마의 나머지 부분을 유지하면서 자체 사용자 메시지 렌더러를 삽입하려면 src/components/copilot/의 관련 파일을 편집하고 index.tsx에서 재내보냅니다.

채팅별 재정의는 테마와 함께 작동합니다 — 슬롯 prop으로 전달하는 모든 것은 테마 기본값을 재정의합니다:

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

사용자 정의 컴포넌트로 슬롯 교체

섹션 제목: “사용자 정의 컴포넌트로 슬롯 교체”

모든 슬롯은 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>를 실행하면 에이전트의 로컬 서버도 시작됩니다
  2. 런타임 구성이 로컬 AG-UI URL(예: http://localhost:8081)을 가리키도록 재정의됩니다
  3. 웹사이트와 에이전트가 함께 핫 리로드됩니다
Terminal window
pnpm nx dev <WebsiteProject>