Name:
interface
Value:
Extend your Amplify Gen 2 app with AWS Blocks — self-contained backend capabilities you compose into your existing backend.
Gen1 DocsLegacy

Page updated Jul 2, 2026

Add an AI agent to your Amplify app

This guide adds a conversational AI agent to an Amplify Gen 2 app using the AWS Blocks Agent Block. The agent streams responses, persists conversations, and authenticates each request against the Cognito user pool your Amplify backend already provisions.

This guide assumes you have already added AWS Blocks to your Amplify project.

Install the Agent Block

Add the Block to your aws-blocks workspace:

npm install @aws-blocks/bb-agent zod

The Agent Block uses Zod schemas (v4) to validate tool parameters, so zod is a required peer dependency.

Define the agent

In aws-blocks/index.ts, create an Agent and expose API methods that authenticate the caller with the Amplify Cognito pool before touching a conversation. The CognitoVerifier scaffolded into your project verifies the same tokens Amplify issues:

aws-blocks/index.ts
import { ApiNamespace, Scope } from '@aws-blocks/blocks';
import { Agent, BedrockModels } from '@aws-blocks/bb-agent';
import { CognitoVerifier } from './cognito-verifier.js';
const scope = new Scope('my-app');
const auth = new CognitoVerifier({
userPoolId: process.env.COGNITO_USER_POOL_ID!,
clientId: process.env.COGNITO_CLIENT_ID!,
tokenUse: 'id'
});
// `model` is optional and defaults to BedrockModels.BALANCED.
const agent = new Agent(scope, 'support-agent', {
model: { deployed: BedrockModels.BALANCED },
systemPrompt: 'You are a helpful support agent.'
});
// These methods return the shapes the `useChat` client hook expects
// ({ conversationId } and { messages }) so the frontend can wire in directly.
export const api = new ApiNamespace(scope, 'api', (context) => ({
// Start a conversation for the signed-in Amplify user
async createConversation() {
const user = await auth.requireAuth(context);
return { conversationId: await agent.createConversationId(user.sub) };
},
// Send a message — the agent streams chunks to the given Realtime channel
async sendMessage(conversationId: string, message: string, channelId: string) {
const user = await auth.requireAuth(context);
await agent.stream(message, { conversationId, channelId, userId: user.sub });
},
// Read history — verify the conversation belongs to this user first
async getConversation(conversationId: string) {
const user = await auth.requireAuth(context);
const owned = await agent.listConversations(user.sub);
if (!owned.some((c) => c.conversationId === conversationId)) {
throw new Error('Not found');
}
return { messages: await agent.getConversation(conversationId) };
},
// Expose the Realtime channel so the client can subscribe to streamed chunks
async getChannel(channelId: string) {
return agent.getChannel(channelId);
}
}));

The Agent Block scopes data by an unguessable conversationId but does not authorize the caller on read paths. Always derive the user from requireAuth(context) and confirm the conversation belongs to them — as getConversation does above — before returning history.

Deploy

The agent runs on Amazon Bedrock, so deploy it with the rest of your backend:

npm run sandbox

Make sure model access is enabled for the Bedrock model your agent uses in your account and Region.

Call the agent from your frontend

Generate the native client for your platform from your backend's blocks.spec.json and attach your Amplify Auth session token as a Bearer token on each request, as described in Connect your frontend. Call createConversation to get a conversation ID, then sendMessage with a channel ID, and subscribe to that Realtime channel to receive streamed chunks.

Next steps