Pular para o conteúdo

Agente TypeScript Strands

Gere um Strands Agent TypeScript para construir agentes de IA com ferramentas e, opcionalmente, implante-o no Amazon Bedrock AgentCore Runtime. O gerador usa tRPC sobre WebSocket para aproveitar o suporte de streaming bidirecional do AgentCore para comunicação em tempo real com segurança de tipo.

Strands é um framework leve para construir agentes de IA. Os principais recursos incluem:

  • Leve e personalizável: Loop de agente simples que não atrapalha
  • Pronto para produção: Observabilidade completa, rastreamento e opções de implantação em escala
  • Agnóstico de modelo e provedor: Suporta muitos modelos diferentes de vários provedores
  • Ferramentas orientadas pela comunidade: Conjunto poderoso de ferramentas contribuídas pela comunidade
  • Suporte multi-agente: Técnicas avançadas como equipes de agentes e agentes autônomos
  • Modos de interação flexíveis: Suporte conversacional, streaming e não-streaming

Você pode gerar um Strands Agent TypeScript de duas maneiras:

  1. Instale o Nx Console VSCode Plugin se ainda não o fez
  2. Abra o console Nx no VSCode
  3. Clique em Generate (UI) na seção "Common Nx Commands"
  4. Procure por @aws/nx-plugin - ts#strands-agent
  5. Preencha os parâmetros obrigatórios
    • Clique em Generate
    Parâmetro Tipo Padrão Descrição
    project Obrigatório string - The project to add the Strands Agent to
    computeType string BedrockAgentCoreRuntime The type of compute to host your Strands Agent.
    name string - The name of your Strands Agent (default: agent)
    iacProvider string Inherit The preferred IaC provider. By default this is inherited from your initial selection.

    O gerador adicionará os seguintes arquivos ao seu projeto TypeScript existente:

    • Directoryyour-project/
      • Directorysrc/
        • Directoryagent/ (ou nome personalizado se especificado)
          • index.ts Ponto de entrada para Bedrock AgentCore Runtime
          • init.ts Inicialização do tRPC
          • router.ts Roteador tRPC com procedimentos de agente
          • agent.ts Definição principal do agente com ferramentas de exemplo
          • client.ts Cliente fornecido para invocar seu agente
          • agent-core-trpc-client.ts Fábrica de cliente para conectar a agentes no AgentCore Runtime
          • agent-core-mcp-client.ts Fábrica de cliente para conectar a servidores MCP no AgentCore Runtime
          • Dockerfile Ponto de entrada para hospedar seu agente (excluído quando computeType está definido como None)
      • package.json Atualizado com dependências do Strands
      • project.json Atualizado com destinos de servir do agente

    Como este gerador fornece infraestrutura como código com base no iacProvider escolhido, ele criará um projeto em packages/common que inclui os constructs CDK ou módulos Terraform relevantes.

    O projeto comum de infraestrutura como código está estruturado da seguinte forma:

    • Directorypackages/common/constructs
      • Directorysrc
        • Directoryapp/ Constructs para infraestrutura específica de um projeto/gerador
        • Directorycore/ Constructs genéricos reutilizados pelos constructs em app
        • index.ts Ponto de entrada exportando os constructs de app
      • project.json Metas de build e configuração do projeto

    Para implantar seu Strands Agent, os seguintes arquivos são gerados:

    • Directorypackages/common/constructs/src
      • Directoryapp
        • Directoryagents
          • Directory<project-name>
            • <project-name>.ts Construto CDK para implantar seu agente
            • Dockerfile Arquivo docker passthrough usado pelo construto CDK

    O Strands Agent TypeScript usa tRPC sobre WebSocket, aproveitando o suporte de streaming bidirecional do AgentCore para permitir comunicação em tempo real com segurança de tipo entre clientes e seu agente.

    Como o tRPC suporta procedimentos Query, Mutation e Subscription sobre WebSocket, você pode definir qualquer número de procedimentos. Por padrão, um único procedimento de assinatura chamado invoke é definido para você em router.ts.

    Ferramentas são funções que o agente de IA pode chamar para executar ações. Você pode adicionar novas ferramentas no arquivo agent.ts:

    import { Agent, tool } from '@strands-agents/sdk';
    import z from 'zod';
    const letterCounter = tool({
    name: 'letter_counter',
    description: 'Count occurrences of a specific letter in a word',
    inputSchema: z.object({
    word: z.string().describe('The input word to search in'),
    letter: z.string().length(1).describe('The specific letter to count'),
    }),
    callback: (input) => {
    const { word, letter } = input;
    const count = word.toLowerCase().split(letter.toLowerCase()).length - 1;
    return `The letter '${letter}' appears ${count} time(s) in '${word}'`;
    },
    });
    // Add tools to your agent
    export const agent = new Agent({
    systemPrompt: 'You are a helpful assistant with access to various tools.',
    tools: [letterCounter],
    });

    O framework Strands trata automaticamente:

    • Validação de entrada usando esquemas Zod
    • Geração de esquema JSON para chamada de ferramenta
    • Tratamento de erros e formatação de resposta

    Por padrão, os agentes Strands usam Claude 4 Sonnet, mas você pode alternar facilmente entre provedores de modelo:

    import { Agent } from '@strands-agents/sdk';
    import { BedrockModel } from '@strands-agents/sdk/models/bedrock';
    import { OpenAIModel } from '@strands-agents/sdk/models/openai';
    // Use Bedrock
    const bedrockModel = new BedrockModel({
    modelId: 'anthropic.claude-sonnet-4-20250514-v1:0',
    });
    let agent = new Agent({ model: bedrockModel });
    let response = await agent.invoke('What can you help me with?');
    // Alternatively, use OpenAI by just switching model provider
    const openaiModel = new OpenAIModel({
    apiKey: process.env.OPENAI_API_KEY,
    modelId: 'gpt-4o',
    });
    agent = new Agent({ model: openaiModel });
    response = await agent.invoke('What can you help me with?');

    Consulte a documentação do Strands sobre provedores de modelo para mais opções de configuração.

    Você pode adicionar ferramentas de servidores MCP ao seu agente Strands.

    Para consumir Servidores MCP que você criou usando os geradores py#mcp-server ou ts#mcp-server (ou outros hospedados no Bedrock AgentCore Runtime), uma fábrica de cliente é gerada para você em agent-core-mcp-client.ts.

    Você pode atualizar a inicialização do seu agente em agent.ts para criar clientes MCP e adicionar ferramentas. O exemplo a seguir mostra como fazer isso com autenticação IAM (SigV4):

    agent.ts
    import { Agent } from '@strands-agents/sdk';
    import { AgentCoreMcpClient } from './agent-core-mcp-client.js';
    const mcpClient = AgentCoreMcpClient.withIamAuth({
    agentRuntimeArn: process.env.MCP_AGENTCORE_RUNTIME_ARN!,
    region: process.env.AWS_REGION || 'us-west-2',
    sessionId: 'my-session-id',
    });
    export const agent = new Agent({
    systemPrompt: '...',
    tools: [mcpClient],
    });

    Com o exemplo de autenticação IAM acima, precisamos configurar duas coisas em nossa infraestrutura. Primeiro, precisamos adicionar a variável de ambiente que nosso agente está consumindo para o ARN do AgentCore Runtime do nosso servidor MCP e, em segundo lugar, precisamos conceder permissões ao nosso agente para invocar o servidor MCP. Isso pode ser alcançado da seguinte forma:

    import { MyProjectAgent, MyProjectMcpServer } from ':my-scope/common-constructs';
    export class ExampleStack extends Stack {
    constructor(scope: Construct, id: string) {
    const mcpServer = new MyProjectMcpServer(this, 'MyProjectMcpServer');
    const agent = new MyProjectAgent(this, 'MyProjectAgent', {
    environmentVariables: {
    MCP_AGENTCORE_RUNTIME_ARN: mcpServer.agentCoreRuntime.agentRuntimeArn,
    },
    });
    mcpServer.agentCoreRuntime.grantInvoke(agent.agentCoreRuntime);
    }
    }

    Para um guia mais aprofundado sobre como escrever agentes Strands, consulte a documentação do Strands.

    O gerador configura um destino chamado <your-agent-name>-serve, que inicia seu Strands Agent localmente para desenvolvimento e testes.

    Terminal window
    pnpm nx run your-project:agent-serve

    Este comando usa tsx --watch para reiniciar automaticamente o servidor quando os arquivos mudam. O agente estará disponível em http://localhost:8081 (ou a porta atribuída se você tiver múltiplos agentes).

    Implantando seu Strands Agent no Bedrock AgentCore Runtime

    Seção intitulada “Implantando seu Strands Agent no Bedrock AgentCore Runtime”

    Se você selecionou BedrockAgentCoreRuntime para computeType, a infraestrutura CDK ou Terraform relevante é gerada, que você pode usar para implantar seu Strands Agent no Amazon Bedrock AgentCore Runtime.

    Um construto CDK é gerado para o seu agente, nomeado com base no name que você escolheu ao executar o gerador, ou <ProjectName>Agent por padrão.

    Você pode usar este construto CDK em uma aplicação CDK:

    import { MyProjectAgent } from ':my-scope/common-constructs';
    export class ExampleStack extends Stack {
    constructor(scope: Construct, id: string) {
    // Add the agent to your stack
    const agent = new MyProjectAgent(this, 'MyProjectAgent');
    // Grant permissions to invoke the relevant models in bedrock
    agent.agentCoreRuntime.addToRolePolicy(
    new PolicyStatement({
    actions: [
    'bedrock:InvokeModel',
    'bedrock:InvokeModelWithResponseStream',
    ],
    // You can scope the below down to the specific models you use
    resources: [
    'arn:aws:bedrock:*:*:foundation-model/*',
    'arn:aws:bedrock:*:*:inference-profile/*',
    ],
    }),
    );
    }
    }

    Por padrão, seu Strands Agent será protegido usando autenticação IAM, basta implantá-lo sem nenhum argumento:

    import { MyProjectAgent } from ':my-scope/common-constructs';
    export class ExampleStack extends Stack {
    constructor(scope: Construct, id: string) {
    new MyProjectAgent(this, 'MyProjectAgent');
    }
    }

    Você pode conceder acesso para invocar seu agente no Bedrock AgentCore Runtime usando o método grantInvoke, por exemplo:

    import { MyProjectAgent } from ':my-scope/common-constructs';
    export class ExampleStack extends Stack {
    constructor(scope: Construct, id: string) {
    const agent = new MyProjectAgent(this, 'MyProjectAgent');
    const lambdaFunction = new Function(this, ...);
    agent.agentCoreRuntime.grantInvoke(lambdaFunction);
    }
    }

    O exemplo abaixo demonstra como configurar a autenticação Cognito para o seu agente.

    Para configurar a autenticação JWT usando Cognito, use o método de fábrica RuntimeAuthorizerConfiguration.usingCognito():

    import { MyProjectAgent } from ':my-scope/common-constructs';
    import { RuntimeAuthorizerConfiguration } from '@aws-cdk/aws-bedrock-agentcore-alpha';
    export class ExampleStack extends Stack {
    constructor(scope: Construct, id: string) {
    const userPool = new UserPool(this, 'UserPool');
    const client = userPool.addClient('Client', {
    authFlows: {
    userPassword: true,
    },
    });
    new MyProjectAgent(this, 'MyProjectAgent', {
    authorizerConfiguration: RuntimeAuthorizerConfiguration.usingCognito(
    userPool,
    [client],
    ),
    });
    }
    }

    Alternativamente, para autenticação JWT personalizada com seu próprio provedor OIDC, use RuntimeAuthorizerConfiguration.usingJWT():

    import { MyProjectAgent } from ':my-scope/common-constructs';
    import { RuntimeAuthorizerConfiguration } from '@aws-cdk/aws-bedrock-agentcore-alpha';
    export class ExampleStack extends Stack {
    constructor(scope: Construct, id: string) {
    new MyProjectAgent(this, 'MyProjectAgent', {
    authorizerConfiguration: RuntimeAuthorizerConfiguration.usingJWT(
    'https://example.com/.well-known/openid-configuration',
    ['client1', 'client2'], // Allowed Client IDs (optional)
    ['audience1'], // Allowed Audiences (optional)
    ),
    });
    }
    }

    O gerador configura automaticamente um destino bundle que utiliza o Rolldown para criar um pacote de implantação:

    Terminal window
    pnpm nx run <project-name>:bundle

    A configuração do Rolldown pode ser encontrada em rolldown.config.ts, com uma entrada para cada pacote a ser gerado. O Rolldown gerencia a criação de múltiplos pacotes em paralelo, se definidos.

    O destino bundle usa index.ts como ponto de entrada para o servidor WebSocket hospedar no Bedrock AgentCore Runtime.

    O gerador configura um destino <your-agent-name>-docker que executa o servidor WebSocket empacotado na porta 8080 conforme o contrato de runtime do AgentCore.

    Um destino docker também é gerado que executa o docker build para todos os agentes se você tiver múltiplos definidos.

    Seu agente é automaticamente configurado com observabilidade usando o AWS Distro for Open Telemetry (ADOT), configurando auto-instrumentação em seu Dockerfile.

    Você pode encontrar traces no Console AWS do CloudWatch, selecionando “GenAI Observability” no menu. Observe que para que os traces sejam populados você precisará habilitar Transaction Search.

    Para mais detalhes, consulte a documentação do AgentCore sobre observabilidade.

    A comunicação do agente é transmitida via tRPC sobre WebSocket. Como tal, é recomendado usar a fábrica de cliente com segurança de tipo gerada em client.ts.

    Você pode invocar um agente em execução local usando o método de fábrica .local da fábrica de cliente.

    Você pode, por exemplo, criar um arquivo chamado scripts/test.ts em seu workspace que importa o cliente:

    scripts/test.ts
    import { AgentClient } from '../packages/<project>/src/agent/client.js';
    const client = AgentClient.local({ url: 'http://localhost:8081/ws' });
    client.invoke.subscribe({ message: 'what is 1 plus 1?' }, { onData: console.log });

    Para invocar seu Agent implantado no Bedrock AgentCore Runtime, você pode enviar uma requisição POST para o endpoint do dataplane do Bedrock AgentCore Runtime com seu ARN de runtime codificado em URL.

    Você pode obter o ARN de runtime da sua infraestrutura da seguinte forma:

    import { CfnOutput } from 'aws-cdk-lib';
    import { MyProjectAgent } from ':my-scope/common-constructs';
    export class ExampleStack extends Stack {
    constructor(scope: Construct, id: string) {
    const agent = new MyProjectAgent(this, 'MyProjectAgent');
    new CfnOutput(this, 'AgentArn', {
    value: agent.agentCoreRuntime.agentRuntimeArn,
    });
    }
    }

    O ARN terá o seguinte formato: arn:aws:bedrock-agentcore:<region>:<account>:runtime/<agent-runtime-id>.

    Você pode então codificar o ARN em URL substituindo : por %3A e / por %2F.

    A URL do dataplane do Bedrock AgentCore Runtime para invocar o agent é a seguinte:

    https://bedrock-agentcore.<region>.amazonaws.com/runtimes/<url-encoded-arn>/invocations

    A maneira exata de invocar esta URL depende do método de autenticação usado.

    O arquivo client.ts gerado inclui uma fábrica de cliente com segurança de tipo que pode ser usada para invocar seu agente implantado.

    Você pode invocar seu agente implantado passando seu ARN para o método de fábrica withIamAuth:

    import { AgentClient } from './agent/client.js';
    const client = AgentClient.withIamAuth({
    agentRuntimeArn: 'arn:aws:bedrock-agentcore:us-west-2:123456789012:runtime/my-agent',
    });
    client.invoke.subscribe({ message: 'what is 1 plus 1?' }, {
    onData: (message) => console.log(message),
    onError: (error) => console.error(error),
    onComplete: () => console.log('Done'),
    });

    Use o método de fábrica withJwtAuth para autenticar com o token de acesso JWT / Cognito.

    const client = AgentClient.withJwtAuth({
    agentRuntimeArn: 'arn:aws:bedrock-agentcore:us-west-2:123456789012:runtime/my-agent',
    accessTokenProvider: async () => `<access-token>`,
    });
    client.invoke.subscribe({ message: 'what is 1 plus 1?' }, {
    onData: console.log,
    });

    O accessTokenProvider deve retornar o token usado para autenticar a solicitação. Você pode, por exemplo, obter um token dentro deste método para garantir que credenciais atualizadas sejam reutilizadas quando o tRPC reiniciar uma conexão WebSocket. O exemplo abaixo demonstra o uso do AWS SDK para obter o token do Cognito:

    import { CognitoIdentityProvider } from "@aws-sdk/client-cognito-identity-provider";
    const cognito = new CognitoIdentityProvider();
    const jwtClient = AgentClient.withJwtAuth({
    agentRuntimeArn: 'arn:aws:bedrock-agentcore:us-west-2:123456789012:runtime/my-agent',
    accessTokenProvider: async () => {
    const response = await cognito.adminInitiateAuth({
    UserPoolId: '<user-pool-id>',
    ClientId: '<user-pool-client-id>',
    AuthFlow: 'ADMIN_NO_SRP_AUTH',
    AuthParameters: {
    USERNAME: '<username>',
    PASSWORD: '<password>',
    },
    });
    return response.AuthenticationResult!.AccessToken!;
    },
    });

    WebSockets no navegador não suportam a especificação de cabeçalhos (além de Sec-WebSocket-Protocol) e, portanto, a fábrica de cliente gerada em client.ts não pode ser usada em um navegador (isso na verdade resultará em um erro de compilação, pois o construtor WebSocket não aceita cabeçalhos como faz no NodeJS).

    Para invocar seu agente a partir de um navegador, você precisa criar uma URL WebSocket pré-assinada usando AWS SigV4.

    O exemplo abaixo mostra um fluxo de ponta a ponta de obtenção de credenciais, criação de uma URL pré-assinada e invocação do agente:

    import { createTRPCClient, createWSClient, wsLink } from '@trpc/client';
    import { AwsClient } from 'aws4fetch';
    import { CognitoIdentityClient } from '@aws-sdk/client-cognito-identity';
    import { fromCognitoIdentityPool } from '@aws-sdk/credential-provider-cognito-identity';
    import type { AppRouter } from './your-agent/router';
    // Build a presigned WebSocket URL
    async function buildSignedUrl(
    agentRuntimeArn: string,
    idToken: string,
    region: string = 'us-west-2'
    ): Promise<string> {
    // Get credentials from a Cognito Identity Pool (or other source)
    const credentials = fromCognitoIdentityPool({
    client: new CognitoIdentityClient({ region }),
    identityPoolId: 'us-west-2:xxxxx',
    logins: {
    [`cognito-idp.${region}.amazonaws.com/us-west-2_xxxxx`]: idToken,
    },
    });
    const cognitoIdentity = new CognitoIdentityClient({ credentials });
    const credential = await cognitoIdentity.config.credentials();
    // Create AWS SigV4 client
    const awsClient = new AwsClient({
    ...credential,
    service: 'bedrock-agentcore',
    });
    // Build WebSocket URL from ARN
    const wsUrl = `wss://bedrock-agentcore.${region}.amazonaws.com/runtimes/${agentRuntimeArn.replace(/:/g, '%3A').replace(/\//g, '%2F')}/ws`;
    // Create presigned URL
    const signedRequest = await awsClient.sign(wsUrl, {
    method: 'GET',
    aws: { signQuery: true },
    });
    return signedRequest.url;
    }
    // Create tRPC client with presigned WebSocket URL
    const agentRuntimeArn = 'arn:aws:bedrock-agentcore:us-west-2:123456789012:runtime/my-agent';
    const idToken = '<your-id-token>';
    const wsClient = createWSClient({
    url: async () => buildSignedUrl(agentRuntimeArn, idToken),
    });
    const trpcClient = createTRPCClient<AppRouter>({
    links: [wsLink({ client: wsClient })],
    });
    // Invoke the agent
    trpcClient.invoke.subscribe({ message: 'what is 1 plus 1?' }, {
    onData: (message) => console.log(message),
    });