AG-UI no Amazon Bedrock AgentCore: interface generativa, estado compartilhado e human-in-the-loop

Quando conversar não é suficiente

Agentes de IA já dominam a arte de conversar. Mas e quando a tarefa exige mais do que texto? Renderizar um gráfico diretamente no chat, manter um painel de tarefas sincronizado em tempo real ou pausar a execução para aguardar aprovação do usuário — essas interações pedem um padrão de comunicação mais robusto entre o backend do agente e o frontend.

É aí que entra o AG-UI (Agent-User Interaction Protocol), um protocolo aberto que define exatamente esse padrão. Ele funciona com múltiplos frameworks de agentes — Strands Agents, LangGraph, CrewAI — e com as principais bibliotecas de frontend como React, Angular e Vue. A grande vantagem: o código do agente e o código da interface ficam completamente desacoplados, permitindo escolher o melhor de cada mundo sem amarrações.

A AWS publicou um guia detalhado mostrando como o AG-UI se integra ao Fullstack AgentCore Solution Template (FAST) e como o CopilotKit expande essas capacidades com interfaces generativas, estado compartilhado e fluxos human-in-the-loop — tudo rodando no Amazon Bedrock AgentCore.

Como a solução está estruturada

O Amazon Bedrock AgentCore Runtime é um ambiente serverless, seguro e dedicado para hospedar agentes de IA e ferramentas. Ele suporta três protocolos principais: o MCP (Model Context Protocol) conecta agentes a ferramentas, o A2A (Agent2Agent) conecta agentes entre si, e o AG-UI conecta agentes aos usuários.

Quando um container de agente é implantado com a flag do protocolo AG-UI, o AgentCore funciona como um proxy transparente: cuida da autenticação (SigV4 ou OAuth 2.0 via Amazon Cognito), do isolamento de sessão, da escalabilidade e da observabilidade. O container precisa expor POST /invocations para requisições AG-UI e GET /ping para verificações de saúde na porta 8080. Para mais detalhes sobre esse processo, a AWS disponibiliza a documentação de como implantar servidores AG-UI no AgentCore Runtime.

O FAST é um projeto inicial pronto para implantação que conecta AgentCore Runtime, Gateway, Identity, Memory e Code Interpreter com um frontend React e autenticação via Amazon Cognito — tudo definido com AWS CDK. A versão v0.4.1 adicionou dois padrões AG-UI (agui-strands-agent e agui-langgraph-agent) que compartilham um único parser de frontend. Para um guia completo da arquitetura e implantação do FAST, vale conferir o post Accelerate agentic application development with a full-stack starter template for Amazon Bedrock AgentCore.

A solução apresentada tem duas camadas independentes. A primeira é o AG-UI integrado ao FAST, com dois padrões de agente e um parser único de frontend que os trata de forma transparente — o frontend não precisa saber qual framework está rodando no backend. A segunda é a amostra CopilotKit + FAST, que substitui a interface de chat nativa pelo CopilotKit, adicionando interface generativa com componentes inline, estado compartilhado bidirecional e interações human-in-the-loop.

AG-UI no FAST: um parser, dois frameworks

Padrão agui-strands-agent

O padrão agui-strands-agent envolve um Strands Agent no StrandsAgent da biblioteca ag-ui-strands. O wrapper traduz automaticamente os eventos de streaming do Strands em Server-Sent Events (SSE) do AG-UI. Cada requisição cria um agente novo com as ferramentas MCP do Gateway. O AgentCore Memory é associado por thread por meio de um provedor de gerenciador de sessão, de forma que o histórico da conversa persiste mesmo durante o escalonamento. A memória é opcional: o provedor retorna None quando MEMORY_ID não está definido:

# patterns/agui-strands-agent/agent.py
from ag_ui_strands import StrandsAgent, StrandsAgentConfig
from bedrock_agentcore.runtime import BedrockAgentCoreApp, RequestContext
from strands import Agent

app = BedrockAgentCoreApp()

# Build the model and Code Interpreter once at module load
MODEL = BedrockModel(model_id="us.anthropic.claude-sonnet-4-5-20250929-v1:0")
CODE_INTERPRETER = StrandsCodeInterpreterTools(REGION).execute_python_securely

@app.entrypoint
async def invocations(payload: dict, context: RequestContext):
    input_data = RunAgentInput.model_validate(payload)
    actor_id = extract_user_id_from_context(context)

    # Fresh agent per request --- picks up the caller's identity and tools
    agent = Agent(
        model=MODEL,
        system_prompt=SYSTEM_PROMPT,
        tools=[create_gateway_mcp_client(actor_id), CODE_INTERPRETER],
        session_manager=get_memory_session_manager(actor_id, session_id),
    )

    agui_agent = StrandsAgent(
        agent=agent,
        name="agui_strands_agent",
        config=StrandsAgentConfig(
            session_manager_provider=make_memory_provider(actor_id),
            replay_history_into_strands=False,
        ),
    )

    async for event in agui_agent.run(input_data):
        yield event.model_dump(mode="json", by_alias=True, exclude_none=True)

O BedrockAgentCoreApp lê os cabeçalhos do AgentCore Runtime (WorkloadAccessToken, Authorization, Session-Id) e popula variáveis de contexto, de forma que a autenticação do Gateway e o Memory funcionam da mesma forma que os padrões HTTP.

Padrão agui-langgraph-agent

Já o padrão agui-langgraph-agent usa o LangGraphAGUIAgent da biblioteca copilotkit. O grafo compilado é construído a cada requisição, garantindo que cada invocação receba as ferramentas MCP com escopo do chamador. O AgentCore Memory também é opcional aqui — o helper retorna None quando MEMORY_ID não está definido, permitindo executar o padrão sem provisionar Memory:

# patterns/agui-langgraph-agent/agent.py
from copilotkit import CopilotKitMiddleware, LangGraphAGUIAgent

async def build_graph(actor_id: str):
    """Build a fresh LangGraph compiled graph with Gateway tools."""
    mcp_client = await create_gateway_mcp_client(actor_id)
    tools = await mcp_client.get_tools()
    tools.append(CODE_INTERPRETER)
    return create_agent(
        model=MODEL,
        tools=tools,
        checkpointer=get_memory_saver(),  # None when MEMORY_ID is unset
        middleware=[CopilotKitMiddleware()],
        system_prompt=SYSTEM_PROMPT,
    )

@app.entrypoint
async def invocations(payload: dict, context: RequestContext):
    input_data = RunAgentInput.model_validate(payload)
    actor_id = extract_user_id_from_context(context)
    graph = await build_graph(actor_id)

    agui_agent = LangGraphAGUIAgent(
        name="agui_langgraph_agent",
        graph=graph,
        config={"configurable": {"actor_id": actor_id}},
    )

    async for event in agui_agent.run(input_data):
        yield event.model_dump(mode="json", by_alias=True, exclude_none=True)

Um único parser para ambos os frameworks

Os dois padrões produzem os mesmos eventos AG-UI — um fluxo de eventos tipados sobre SSE. Por exemplo, uma única chamada de ferramenta gera esta sequência:

data: {"type": "RUN_STARTED", "threadId": "t1", "runId": "r1"}
data: {"type": "TEXT_MESSAGE_START", "messageId": "m1", "role": "assistant"}
data: {"type": "TEXT_MESSAGE_CONTENT", "messageId": "m1", "delta": "Let me check "}
data: {"type": "TEXT_MESSAGE_CONTENT", "messageId": "m1", "delta": "that for you."}
data: {"type": "TEXT_MESSAGE_END", "messageId": "m1"}
data: {"type": "TOOL_CALL_START", "toolCallId": "tc1", "toolCallName": "get_weather"}
data: {"type": "TOOL_CALL_ARGS", "toolCallId": "tc1", "delta": "{\"location\": \"Seattle\"}"}
data: {"type": "TOOL_CALL_END", "toolCallId": "tc1"}
data: {"type": "TOOL_CALL_RESULT", "toolCallId": "tc1", "content": "{\"temp\": 55}"}
data: {"type": "RUN_FINISHED", "threadId": "t1", "runId": "r1"}

O parser de frontend mapeia cada evento para uma ação correspondente:

// frontend/src/lib/agentcore-client/parsers/agui.ts
export const parseAguiChunk: ChunkParser = (line, callback) => {
  if (!line.startsWith("data: ")) return;
  const json = JSON.parse(line.substring(6).trim());
  switch (json.type) {
    case "TEXT_MESSAGE_CONTENT":
      callback({ type: "text", content: json.delta ?? "" });
      break;
    case "TOOL_CALL_START":
      callback({ type: "tool_use_start", toolUseId: json.toolCallId, name: json.toolCallName });
      break;
    case "TOOL_CALL_RESULT":
      callback({ type: "tool_result", toolUseId: json.toolCallId, result: json.content ?? "" });
      break;
    case "RUN_FINISHED":
      callback({ type: "result", stopReason: "end_turn" });
  }
};

Diferente dos padrões HTTP — onde Strands, LangGraph e Claude Agent SDK exigem parsers separados para seus diferentes formatos de streaming — o AG-UI abstrai o framework do backend. Trocar agui-strands-agent por agui-langgraph-agent na configuração não exige nenhuma mudança no frontend.

Para implantar, basta definir o padrão em infra-cdk/config.yaml e executar o CDK:

backend:
  pattern: agui-strands-agent  # or agui-langgraph-agent
  deployment_type: docker

cd infra-cdk
cdk deploy --require-approval never
python3 ../scripts/deploy-frontend.py

CopilotKit + FAST: indo além do chat

O frontend base do FAST oferece uma interface de chat funcional, mas o AG-UI suporta interações muito mais ricas. O CopilotKit é uma biblioteca React construída especificamente para esses padrões avançados. A equipe do CopilotKit desenvolveu uma aplicação de exemplo sobre o FAST que demonstra essas capacidades no AgentCore, com suporte tanto para LangGraph quanto para Strands — a escolha é feita no momento da implantação.

Interface generativa: componentes React renderizados pelo agente

Com o CopilotKit, o agente consegue renderizar componentes React customizados diretamente no chat, não apenas texto. O frontend registra componentes que o agente pode invocar por meio de eventos de chamada de ferramenta do AG-UI:

// Register a pie chart the agent can render
useComponent({
  name: "pieChart",
  description: "Displays data as a pie chart.",
  parameters: PieChartPropsSchema,
  render: PieChart,
});

Quando o agente chama a ferramenta pieChart, o CopilotKit intercepta os eventos TOOL_CALL_START e TOOL_CALL_ARGS e renderiza o componente PieChart diretamente na conversa. O agente primeiro chama uma ferramenta query_data para buscar dados de um arquivo CSV de exemplo e então passa os resultados para o componente de gráfico.

Estado compartilhado: canvas de tarefas sincronizado em tempo real

A amostra inclui um canvas de tarefas com sincronização bidirecional entre o agente e a interface. Ao pedir ao agente “Adicione três tarefas: design da API, escrever testes e implantar em staging”, ele chama manage_todos e o canvas é atualizado em tempo real via eventos STATE_SNAPSHOT do AG-UI. Edições feitas diretamente na interface também são visíveis para o agente na próxima invocação, porque o padrão Strands injeta as tarefas atuais no prompt do sistema:

def state_context_builder(state: dict) -> str:
    todos = state.get("todos", [])
    if todos:
        return f"\nCurrent todos:\n{json.dumps(todos, indent=2)}"
    return ""

Human-in-the-loop: o agente pausa e aguarda sua decisão

A amostra demonstra um agendador de reuniões onde o agente pausa no meio da execução e renderiza um seletor de horário. O usuário escolhe um horário e o agente retoma com essa informação:

useHumanInTheLoop({
  name: "scheduleTime",
  description: "Schedule a meeting with the user.",
  parameters: z.object({
    reasonForScheduling: z.string(),
    meetingDuration: z.number(),
  }),
  render: ({ respond, status, args }) => (
    <MeetingTimePicker status={status} respond={respond} {...args} />
  ),
});

O mecanismo usa o fluxo de chamada de ferramenta do AG-UI: o agente emite TOOL_CALL_START para scheduleTime, o CopilotKit renderiza o seletor no lugar de executar uma ferramenta no backend, e a resposta do usuário volta como um TOOL_CALL_RESULT.

Pré-requisitos e como implantar

Para seguir o guia, você vai precisar de:

  • Uma conta AWS com permissões para AWS CloudFormation, Amazon ECR, Amazon Bedrock AgentCore, Amazon Cognito e AWS Amplify.
  • AWS CLI v2 instalada e configurada.
  • AWS CDK instalado.
  • Node.js 18 ou superior e Python 3.11 ou superior.
  • Docker em execução, para builds de container.
  • Acesso ao modelo habilitado no console do Amazon Bedrock para o modelo utilizado pelo agente.

Para implantar a amostra CopilotKit, clone o repositório de amostras FAST e execute:

git clone https://github.com/aws-samples/sample-FAST-applications.git
cd sample-FAST-applications/samples/copilotkit-generative-ui
cp config.yaml.example config.yaml
# Edit config.yaml --- set stack_name_base and admin_user_email
./deploy-langgraph.sh  # or ./deploy-strands.sh

O script provisiona toda a stack: pool de usuários do Amazon Cognito, repositório do Amazon ECR, AgentCore Runtime, AgentCore Gateway, AgentCore Memory, a Lambda do CopilotKit Runtime com Amazon API Gateway e hospedagem no AWS Amplify. Ao final, basta abrir a URL do Amplify exibida no terminal e fazer login para verificar a implantação.

Limpando os recursos

A solução implanta dois stacks separados. Para evitar cobranças contínuas, remova o que foi implantado.

Para remover a implantação FAST:

cd infra-cdk
npx cdk destroy --all

Para remover a amostra CopilotKit:

cd sample-FAST-applications/samples/copilotkit-generative-ui
npx cdk destroy --all

Se um repositório do Amazon ECR ainda contiver imagens de container, exclua-o manualmente — algumas configurações do CDK mantêm repositórios no lugar após o destroy.

Conclusão

A integração do AG-UI ao FAST permite alternar entre os backends Strands e LangGraph sem tocar no código do frontend. A amostra CopilotKit vai além, adicionando interface generativa, estado compartilhado e interações human-in-the-loop — tudo rodando no AgentCore com autenticação gerenciada, escalabilidade e memória.

Para explorar mais, os recursos disponíveis incluem o repositório FAST (para implantar um padrão AG-UI com agui-strands-agent ou agui-langgraph-agent), a amostra CopilotKit Generative UI (para experimentar interface generativa, estado compartilhado e human-in-the-loop no AgentCore), a documentação AG-UI do AgentCore (contrato completo do protocolo e detalhes de implantação), a especificação do protocolo AG-UI (tipos de eventos e design do protocolo) e a documentação do CopilotKit (guia de integração de frontend para interface generativa). Dúvidas e feedback podem ser registrados como issues no repositório FAST ou no repositório FAST Samples.

Fonte

Build generative UI for AI agents on Amazon Bedrock AgentCore with the AG-UI protocol (https://aws.amazon.com/blogs/machine-learning/build-generative-ui-for-ai-agents-on-amazon-bedrock-agentcore-with-the-ag-ui-protocol/)

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *