🦄 Making great presentations more accessible.
This project enhances multilingual accessibility and discoverability while preserving the original content. Detailed transcriptions and keyframes capture the nuances and technical insights that convey the full value of each session.
Note: A comprehensive list of re:Invent 2025 transcribed articles is available in this Spreadsheet!
Overview
📖 AWS re:Invent 2025 - Autonomous Web3 agents on AWS (DAT457)
In this video, the presenters demonstrate building a Web3 agent using Amazon Bedrock AgentCore and the Strands Agents SDK. They walk through live code showing how to implement three key capabilities: blockchain and market data access via browser tools, long-term memory using AgentCore Memory with custom hooks for user preferences and conversation history, and agent-to-agent communication to invoke specialized agents. The demo includes Docker-based deployment to AgentCore Runtime with session isolation, integration with CoinMarketCap for cryptocurrency data, and a practical example of using AWS KMS to manage Ethereum wallet keys and sign transactions on the Sepolia testnet. All code is available in their public GitHub repository.
; This article is entirely auto-generated while preserving the original presentation content as much as possible. Please note that there may be typos or inaccuracies.
Main Part
Introduction to Building Web3 Agents with Amazon Bedrock AgentCore
Awesome, thanks very much for being here late in the afternoon. By Wednesday, I've been to this event five times. It's really tiring both for attendees and for people that work here and presenting. So thanks for being here, and welcome to our code talk about Web3 agents. Today what we're going to do is facilitate a technical session. We're going to show you some live code, walk through the code, what it does, why we made some of the decisions we did about services and primitives that we use. We'll also demonstrate and show you how the pieces fit together, how they work, and what the value of doing things this way would be.
A couple things that I want to call out up front. You're going to hear a lot about AgentCore, which I'm sure you've heard a lot about this whole week. So both excited to share how we're using it with a Web3 flavor. The takeaway from today is how you can use some of those primitives from AgentCore to build an agent that's capable of becoming a Web3 assistant. Then there are of course ways you can extend that for your own use cases, and we'll talk about some of those opportunities.
The other thing is I want to talk about what that agent is going to be able to do and what sort of the run of show is going to look like. So this is one of our general agenda for the day. A code talk, again I mentioned, walking through live code with you, talking about it, and we'll do some introductions of the different Amazon Bedrock AgentCore primitives as we introduce them in our code. But what are the requirements for this Web3 agent? So we thought about what some of the baseline needs someone would have to make an agent valuable for a Web3 customer, a user that's in the Web3 space, the Web3 enthusiast.
First and foremost, it needs to have context from blockchain, so blockchain data, but also market, right? If you're interested in news, sentiment, prices, et cetera. So we want an agent that is able to go get that data that it needs to act on the prompts from the user. Secondly, it needs to have memory, right? It needs to be able to remember user preferences, be able to recall and search through previous conversations and state from previous conversations, so remembering facts about a person, what chains do you use maybe, what addresses do you have, even balances and things like that. So we want our agent to have memory, to be stateful.
And then lastly we also want our agent to be able to trigger or invoke other agents that specialize in a given task. So today we'll show you sort of a reference of an agent that can sign and broadcast transactions or get balance for a given address or wallet on chain. That's on Ethereum, right? Yeah, on Ethereum. And so I think the last thing I want to say is this agent is not intended to be like a robo advisor or to execute trades or trade intent. So I just want to call that out up front. Think of it as an assistant, not something that's going to make trades for you.
And then lastly, I'm going to put a QR code up on the screen now, so you can actually follow along. You can go to the repository. All the code that we're going to be using today is in here as well as, it's not a Jupyter notebook but like a markdown file with all the steps that we're going to go through today. So if you wanted to go and run this yourself, dive a little deeper, we only have, you know, 60 minutes, so we can only talk about everything in so much detail, you can go ahead and do that. So with that, David, let's fire it up and switch views.
Workshop Overview: Architecture and Interactive Session Setup
Right. So what we see here, this is actually the public GitHub repository that we are using today and I switched to the workshop folder. And here we have basically the entire outline of the session, what we're planning to do today. So you can actually also look into it and there's like a technical explanation for every single step enlisted here. Back to you, Forrest. Yeah, absolutely. So I think the first, you know, the preliminary setup that we're going to have at the beginning, the first bit of code that David's going to walk through is a baseline agent that's going to be capable of searching the web and capable of adopting memory, so creating long-term memory using AgentCore memory. We're going to deploy that agent using AgentCore Runtime.
I think one of the most important things that I want to call out for AgentCore Runtime, obviously it's an environment where you can deploy and operate your agents, and I think that's very clear, but one of the things that I want to call out about AgentCore Runtime is particularly important, I think, for use cases like this related to Web3 is session isolation. So when you run an agent session, you invoke an agent with the session ID, it creates its own micro VM with isolated compute memory and file system for storage. So if you think about let's say an
agent that helps users process transaction history to generate an opinion for cryptocurrency taxes, for example, you don't want sessions being mixed between different users where they're pushing really sensitive information like transaction history, XPub public keys, addresses, and so on. All of those things you want to make sure are isolated and kept separated from other users. And so that's one thing I wanted to call out about Bedrock AgentCore runtime and something to keep in the back of your mind as we talk about or we start doing the deployment.
Do you want to move to the architecture, David? And so this is sort of the end state of where we're going to get for the part that we build with you here. There are some other components that it'll interact with. I think there's another architecture diagram later that we can show you, but generally speaking, this is where we're going to land at the end of the session today. Obviously, we're using Bedrock AgentCore runtime, which I just mentioned, and we're using the Strands Agents SDK, but you could execute this sort of the same setup with any other agent framework that you prefer. So we chose Strands, but you could choose something else like LangChain, for example. We're also going to be utilizing observability for logging. We're also going to be using a browser tool, the Bedrock Browser Tool, to get access to some of that data that we want from things like block explorers. So David, let's maybe start with the first round of work.
All right. So we also want to call out that this session is really intended to be interactive. So if you have questions, if you want to do a deep dive into certain things, please don't hesitate to ask us. There's a lot of content here for certain things. As Forrest said, we will use Bedrock, we will use the memory part. You probably have seen some of that stuff already in other workshops. We're using it, but we want to actually also get to the end for the Web3 specifics here. So we will not spend too much time on the Bedrock AgentCore part. We will not spend too much time on the memory, how that works, the hooks. We will call out the most important things, but if you feel that you want to have certain things explained a bit more, please ask us because we do not really have too much time here. We are roughly 50 minutes left. And then also afterwards, if you have questions, we are outside. Please do not hesitate to reach out to us, talk to us, connect with us, or look into the repository.
Setting Up the Development Environment with UV and Docker
All right, so with having that said, this particular folder or this particular workshop that I'm showing, we have all the code examples in here. These particular code examples are also in the code folder that I will be using today. So this is basically the folder that you're seeing over here. And what we will do is we are using a Docker-based approach, so something that is actually really close to production. So we are assuming, okay, you have an agent that you want to build. We're using a Docker build process. We're pushing it to ECR, basically to a container repository, and we are actually fetching it from there. So you will see this, and this is actually because it is really closer to production instead of using any of the wrapping tools or bootstrapping tools for this.
All right. Also, if you're following through on your own machine, there are a certain set of policies required in the IAM policy, for example, for a CLI to deploy these things. Pointing it out for sure, you need a couple of Bedrock and Bedrock AgentCore requirements, but we have these things actually listed in the readme or in the workshop file as well. All right, so the first module is actually now we will now create a base Strands agent using with memory support, basically. To do that, we have UV init, so UV is a next-generation Python package manager. The readme or this particular workshop file explains how you set up everything, how you're creating it. You run UV init, you run UV add, and then add Boto3, the Python dependencies, Bedrock AgentCore, and Boto core, as you see on the screen here. We have the UV lock, and we have this file. Basically, the code folder has been initialized as a UV project. So I can now run UV or use UV run to run our commands. That basically means we have all the requirements, all the dependencies, the Python dependencies in the folder.
I also created a virtual environment, so I have my venv folder here from UV venv, so you could actually even source it from there. What we did is we have the UV folder, or in this folder we have the base requirements to run the scripts later on, for example, the deployment or the agent creation. So the Boto3 and the Python dependencies are in this folder, and we have a dedicated requirements.txt in here. This particular requirements.txt basically points out all the requirements, all the Python requirements for our Strands Agent, and I don't want to go too deep into these things. We have Strands Agent Core, the core dependencies. Playwright is one of these browser-related tools that we'll have in the Lambda that we need in one of the build-out steps for the Strands Agent when we're using the browser, and we will use Boto3 later to invoke another agent, so there's some sort of agent-to-agent communication, basically, that we're looking to do as well.
Also, what I want to point out is another stack, so we have the bigger, overarching repository that we are looking into here. It's called Crypto AI Agents. There's another cryptographic crypto agent in place that I already pre-deployed. These requirements, the sources, and all these things are all in the repository. So everything is in this repository, but what I did in this particular account is I already pre-deployed the Crypto AI Agent because this is a bit more effort, and I'm actually going to invoke it or integrate our Strands Agent with that Crypto AI Agent later on. But we will actually talk about that in more detail when we are at the last build-out step.
All right, so the first agent that we are creating is basically, as I mentioned before, we have a couple of core dependencies. There is Strands Agent, and there's the Memory Client that we are using over here. Give me one second. Just to create the core memory, because Strands or Bedrock AgentCore supports memory, and memory is a core functionality if we are building out a Web3-related agent because we need to explain a couple of things. We need to tell it, okay, what are we interested in? Is there a specific coin? Is there a specific role that I'm having? So we need some sort of long-term memory, and this particular long-term memory we are setting up before. There is a script called create_web3_agent_memory.py. We can run this, and we have a couple of different memory strategies defined in here that are being used later on.
Implementing Long-Term Memory with AgentCore Memory Strategies
I can talk a little more about the memory strategies. So when we were designing this and working on this, we started researching how you'd go about building agent memory from scratch. So how would you go about doing this if you were to set this up yourself without using AgentCore? It's relatively straightforward to use open-source tooling to create memory, put raw data somewhere, and give your agent access to that. When we started doing a little bit more research on how you would actually utilize this in a practical sense, we started testing it with AgentCore memory. So just a couple of things about how this works. AgentCore memory has the short-term memory, which is raw data. So basically, as events get created by your agent, those get stored as raw data in a short-term data store for short-term memory.
If you enable long-term memory and you have memory strategies for things like summarization, semantic search from previous state, or user preferences, there's an asynchronous automatic process that pulls events from that raw storage short-term memory and creates vector embeddings for it and stores it in a vector store for long-term memory. You can configure how long the time to live is for that data, so how long the data will persist. I believe that the time scale for that is a year that you can extend it to. The default is seven days, and that's what we're using here. I think the real value is in this piece here that you see on the screen, so the pre-built memory strategies for long-term memory, because it cuts down a lot of the complexity and the time it takes to build a vector store-based approach, especially for things like semantic search and summaries of previous conversations that you have. So when we start demonstrating this agent, you'll see it remembers some of the previous conversation that we've had with it, or I guess that David's had with it. All right, so we have memory.
The next step, and this again, the workshop guide asks you to create this Web3 agent memory, and you'll see. I already have my file in here, so I actually have these things copied over. The next thing that we need to do is for sure we need to tell our entire infrastructure where do we want to deploy this, the AWS account ID. I already have my account set up that I want to deploy it into.
All right, there we go. Now when you're running this on your own, what you need to do is basically uv run web agent memory.py, and this will actually return a memory ID. This memory ID is very important. We will remember and we will use this later on. I already did or created this particular one. We will see that we will see this memory ID actually later on again, but I have it in an environment variable now in my terminal right now.
Also, to be a bit faster with how we do the memory integration, the next thing is that we have a memory.py file which will automatically be added to the Dockerfile as well. Memory.py is basically just a helper module that we will use for our Strands Agent. Memory.py has in this class, this LongTermMemoryHooks provider that we have defined for our agent here. This is the constructor. We're passing the memory ID over to it later on so that we know which particular memory store to talk to. We have the function retrieve user context. We have save conversation and then basically we have to register hooks so that every time the user, our Web3 analyst or the Web3 person, every time we are interacting with the agent, the agent basically is triggered, these hooks are being triggered, and we are actually saving this information in a long-term memory.
All right, so this is basically in the memory.py. Again here I have everything in my memory file. The next thing to build out a base Web3 agent, we have something called the Strands Agent streaming memory. We have a file or we have this particular Strands Agent. Strands Agent you might have seen it already or probably have seen it already if you have participated in another session here at re:Invent. If not, we will just quickly walk through it. We're using async IO for non-blocking interaction. We have imported these Strands, the Agent and the tool. Tool we will use for later for our tool integration of the crypto AI agent stack. And then we are actually importing MemoryClient from Bedrock AgentCore Memory and this particular import that you're seeing here, this is basically where we import the LongTermMemoryHooks from our memory file that we have previously created. Besides that, everything is basically a standard agent. We have a hardcoded user ID here right now for our demo. And what we did is we have a little tool. This is basically just get version so that we know which particular agent we're interacting with in case that something goes wrong with the deployment.
Building and Deploying the Base Strands Agent with System Prompts
And then we have the system prompt, which is basically now specifying the Web3 user requirements. You want to mention a few things about that? Yeah, so we've created a handful of different types of agents, some that are a little more specialized, some that are more general in nature. Obviously this one is more general, but I think that system prompt is one of the best places for helping specialize that agent for a specific task. So I think I recognize a couple of faces from the session we had, I think it was like an hour and a half ago, about blockchain data. So we had a blockchain data analyst agent, and so in the system prompt there we provided a bunch of tips, best practices and patterns for how blockchain data is stored and queried. And again for an assistant, this is a place where as you test this agent incrementally, you would add additional steering here for which tools to use based on which prompts, what data. Also for memory, you can also kind of give the agent autonomy in determining what should be stored in memory and what shouldn't be. So what we have here is relatively simple. We'll add to it sort of throughout the session.
Again, this is a place where you can customize your agent a lot. Down here we see we have our memory hooks integrated within the hooks provider, and we have the tool where we are actually just passing the get_version right now.
Last but not least, for our model, we are providing this as an environment variable. We actually will talk about this in the next step with the Docker, but we're using Claude Sonnet for this so that we are actually known which inference or which model, which LLM we are using for this. Last but not least, in Strands we have this app entry point, basically the agent invocation, and what we do is we have a stream agent, a stream sync, so that basically means that we do not wait for the LLM or for the full response to be created. We're streaming everything back, and you will see this in our client now, so we thought that in an interactive streaming client it's a bit more interactive for a session like that.
Also, what you can see here is basically these are just a few, a couple of debug statements. If you want to get some more information about tool use, about the reasoning of the model, you could actually uncomment this, and then you will actually see how the model reasons about certain tools and returns these things in the stream as well. But this we will not do today because that would actually be very noisy, and it's really good for debugging but not that good for our thing. So this particular agent that I've now shown is living in strands_agents_streaming_memory.py. We have this exactly over here, so we're almost done.
So we have a Strands agent defined, we have memory set up. As I mentioned, the memory, I ran this before. The memory database creation takes a couple of minutes, so we have a memory in place already, and I have this memory ID. You will see it later on. Now to build everything, we need Docker for this, and we can actually see Docker PS, Docker version. We see we have Docker installed. There is no specific requirement. It is just that we're using a Docker-based build, so you need to have Docker on your machine, or you need to have some remote Docker or remote build engine somewhere.
Now let's have a quick look on how we can integrate and how we can deploy our agent. Again, we are using Docker, so what is required for Docker? We require a Dockerfile. Here we have our Dockerfile listed. It's very simple in this case. We're using a Python base image. We are copying and installing the requirements. These are the requirements that we defined in the beginning, so these are basically just the Strands agent requirements where we have the browser integration and where we have the Boto3. Then we also install an OpenTelemetry distro in this particular Docker image or in the Docker container. This is really so that we can separate the operational piece from the application, so that is just what we are doing over here.
Then we are setting the AWS region where we want to deploy it. We are setting up the inference profile. This is the cross-region inference profile that we're using for Claude Sonnet over here. How can we see this? This is now actually cross-region for the US. You will see, so we're deploying our agent in EU, so it's running in Frankfurt. You will see the changes in a moment. And then last but not least, we have our memory ID that we are also passing into the Docker container, and a lot of these things today are really just optimized for a demo. This is basically what we're passing, the parameters in that way.
Now, if we just have a quick look on how this, what is different in my Dockerfile over here, we see instead of US East One, we have EU Central. Instead of the US cross-regional profile, we use the EU. And then basically we have the memory already in there, and then for the later agent we have a couple of references for the other agent, but we will talk about this in the next step.
Right, so what is the base requirement to build such a Docker or such an agent? Base requirement is that we have a repository. I created a repository, but if you're running this code, you will actually get your ECR repository back, and then you basically just need to log in into this.
If this is too fast or if you need me to explain how you're actually building up the infrastructure, please do not hesitate to ask questions. Someone asked what's the architecture for the Docker. The required architecture is ARM64. For example, if you were doing this in an environment where you're using AMD, you can use Docker Buildx to do cross-platform builds, but the expectation is ARM64. You see, this is exactly what we're doing here. We're using the Buildx because ARM64 is the target basically.
It's no big deal on a Mac machine, but if you're doing this on an x86 system, you need to have some sort of cross compiler. In fact, if you're building this on CloudShell, you'll run into this issue because the architecture is different. All right, so now what I will do is make sure that I have the most recent credentials in here, and then we're triggering the Buildx basically and pushing it up to our repository. This is basically everything that is integrated in this command. Docker Buildx build, we have our platform specified, and then we have our target repository in here as you see, and then we're pushing it. Okay, with credentials, Docker is going through. There we go.
Perfect. So now we have our Strands agent, and we have pushed it to the ECR repository. Now there is also one more thing. As you know, you cannot do anything on AWS without proper IAM policies. So we have another step that is required for the deployment. There's a create agent runtime role. This is the runtime or the IAM policy required for our Bedrock AgentCore. Here we have the invoke model defined, we have the ECR permissions and all these things, and if you're running this, you will get this particular agent core execution role. In this particular workshop or in the file, we will actually iteratively add more permissions so that with more features we are always adding additional IAM permissions so that we follow the least privilege policy as well. We have a least privilege IAM role in a folder in the repo now.
All right, so then there's also deploy agent. Deploy agent is a small Python script, a Python helper that I created for this. This basically is just using Boto3 Bedrock AgentCore control and then says client create agent runtime. This particular client create agent runtime creates a new Bedrock AgentCore runtime that we will then use. What we do is we're pointing that particular runtime to our ECR repository. This is our repository so that that runtime knows, okay, we are always pulling our containers from this particular repository, and we are passing the IAM policy to it. This is what we see here, the role ARN. It's basically our web searching core execution role. If you're running the deployment, you will then see, okay, AgentCore runtime created successfully runtime ARN. Because I created it and we will actually come to this later, what I will do instead, I will not run create, I will run another script which is actually, oops, update agent, because I had these things pre-deployed.
If you have no Bedrock AgentCore environment, you just run the create one, otherwise you run update. All right, now we are getting back the agent runtime ARN, and this particular runtime ARN we're putting into an agent runtime environment variable. This one is basically, this is our runtime, the AgentCore runtime ARN that we are using. Now we are using an invoke agent async file, so this is also, we have a small terminal in here, a streaming client that we can now interact with this particular agent.
This file is called invoke agent async, and this is actually now what we can use to interact with our agent. And this particular streaming terminal basically for our interaction with our agent is sourcing this agent runtime, so this is how it knows what particular Strands agent to talk to. Then you copy this particular one also in your file, and then we go and interact with our agent for the first time.
Testing Memory Functionality and Session Isolation in Production
So this is again a UV run invoke agent async. This is a random session ID that we're creating every time, so how are we doing? Let's see if our agent is responding. All right. So now as you see I've set these things up a bit to speed up the process. It kind of remembers I told it my name is David, so hi David, based on our previous conversation. I told it that I was interested in some of the crypto related things. It remembers that, and now it's actually recalling the previous conversations. So now it knows what does it know in the Web3 space about me? Let's see, it knows something about Bitcoin and Ethereum.
And now we can actually also tell it for future conversation, please also include, is there a preference? Solana. So this is actually now how we are building up our preference. There we go. And what we have seen now, it has already updated our portfolio focus. Now every time we're interacting with it, it will also return everything from Solana. Yes, I see. Using and not, is that? No, so what you're referring to is basically this other stack that you're referring to. There is a default parameter for the Polygon RPC, but you can update the RPC endpoint. But the RPC endpoint is then again just required if you're doing a direct interaction with the blockchain itself.
If you're for example asking for a specific account, like a balance of an account or certain things, we are more on a high level right now. We are not yet interacting with this because the RPC endpoint is really the other stack, the other agent that it requires. So for the portfolio focus, do you have a single place where the memory is, or do you have, okay, I have some memory about this is the portfolio focus, this is the stuff that I should be including in my outputs, and then this is user information over here in this place, like splitting up our memory into multiple kind of focuses, or just keep it all together and let the model figure it out?
Yeah, so there are options there. So the built-in strategies and the memory hooks will basically usually use reasoning to determine what needs to be stored and where in terms of from a user ID and session ID perspective. The memory is namespaced and encrypted, so it's also kept separate. Otherwise it would defeat the purpose of session isolation and at the runtime layer. But there's also the option to do custom strategies that extend the default behavior of some of these default strategies that we showed, and then there you can sort of predefine what types of insights need to be stored where, stored together. And obviously this is even more helpful in long-term memory from a vector embeddings perspective.
So you have either the more out of the box method or a more custom method. And is the custom method, is it basically just natural language, whatever? Yes, there are ways to do it in natural language, but then there's also ways to do it logically when you set up your memory provider and memory hooks. Yeah, absolutely, and this stuff is documented, and I can get with you after and show you the documentation for it. Any other questions we can answer while we're at a stopping point? Yeah, how would you be able to distinguish between my different customers?
That's a great question. Different customers might have different preferences. One might want one thing, and another might want something else. Precisely, yes. When David briefly showed the Dockerfile, I think it was, he defined in there a user ID. In a production agent where you have many users, you would obviously have dynamic user IDs. You might be tying into an identity platform. You have OAuth, for example, where you have user IDs. Then each session that's opened would first check the user ID, and that's what you would namespace memory for. So you have all of your users' memory separated, and then that would resolve that issue. Each user has their own preferences, their own conversation history, list of previous sessions, and so on. Great question. For the sake of this demo, we wanted to simplify it, but in reality, in production, you would have everyone with different user IDs, and that's how you would resolve that.
Yes, and the memory, sorry, could you repeat the question about the memory? That's a good question. I don't know the answer to that. I don't want to tell you the wrong thing, but I will get you an answer on whether the memory is queryable separately. I know you can access it from multiple agents, but I don't know if you can do it from some other client directly. Any other questions before we move on to the next version of this agent? We're building some incremental features on top. Awesome.
Alright, David, one thing before you jump in. I also want to call out the build process and the iterative nature of it. The build process generally remains the same. You change code in your agent, you build a Docker image, you push it to ECR, and then you either create a net new agent or you update your existing agent. This is really compatible with CI/CD processes and so on. Agent Core Runtime works really well with this pattern because it supports versioning. As you create new versions of an existing agent by name, it will point the endpoint for that agent to the latest version, but you also have control over this. You can start to separate multiple versions of agents with different endpoints, so you can separate environments. You can do development, staging, and production, each with a different version of your agent code. Or you can start to diverge the behavior of those agents and separate them by endpoints as well. So you have a lot of control over this. The default behavior is handled for you, obviously, which is just directing the agent invocation endpoint to the latest version, but you can control that either via API or from the console.
Adding Browser Access for Unstructured Web3 Data Gathering
Right, yes. Now let's talk about the next iteration. What we will do now is actually use browser access for the agent. If we want to have an agent that is supposed to query current information, there's always a way. We can go to some predefined REST APIs, for example. There are plenty of REST APIs out there that provide market information. But there are other web pages that provide a lot of information, sentiment analysis, and all these things, basically directly for free. The data is unstructured. Usually the other APIs are super structured. They provide proper JSON, but that again requires a lot of work to integrate. So we thought, okay, for Web3, let's use some browser-related things as well.
Also, just to follow the process, as I mentioned before, you always have to increase IAM permissions. What we will do, or what I did, is actually for the policy, there's a script that allows us now to use the Bedrock AgentCore Browser feature. It includes all the permissions required for browser access. You copy this particular file to your file system, and then you run it. Every time you run it, you will get your AgentCore execution policy updated. I did this before so that we can actually save a bit of time here.
Now we are looking at the Strands agent. Browser use is basically being added in here. We have Playwright, and we have the Bedrock AgentCore Tools Browser client that we will see. If you log in on the console, you will also see browser sessions coming up. Besides that, we have a tool defined now for our Bedrock agent, for our Strands agent. This tool is called get coin data. We have Playwright, and we have a tool called get coin data with browser. This is calling this method.
This method is where we define the browser session. We're passing the region and all this information into it. The region is being sourced from an environment variable. What it basically does is we want to use CoinMarketCap in this case. We want to just go to CoinMarketCap and get the coin-specific information and then basically process it. Then we basically consume this data in the LLM and we analyze it, and then hope that it provides good information for us.
That's basically what we have here now. I will exit this particular file, and you'll see I have my Strands Agents Memory Browser dot py file in here. What we can now do is when it's like the Docker file, I can do this now with the Dockerfile because the Dockerfile includes the entire directory, like all the files, and I'm just basically telling my process in the Docker which particular tool or which particular Strands Agent version to call. That's why I can just type in the browser and it gets scanned automatically.
What I do now is I just do the Docker buildx. We're basically building the next version now. This particular Dockerfile is using the browser-enabled Strands Agent, and we are running the UV run update agent. Basically, we're pulling the latest Docker version for our Strands Agent. While we wait, the browser tool that we're using here is the one that's available in AgentCore. It's the built-in tool that's available through AgentCore. It's a headless browser that allows you to automate a lot of different browser tasks.
Here we're using it to get coin data instead of using a structured set of APIs because it allows us to get a broader set of data more easily. It's also something you could use pretty readily for doing some general sentiment analysis by pulling from news syndication websites and other things like that, which we did test when we were building this. All right, so this is why I just had it like this tiny little version thing, so I wanted to see what version it is. In this case, it is now the agent with memory and browser.
Let's provide, and we see, provide some market data for my crypto. It'll figure it out. Yeah, it will figure it out. Now it should actually use the browser, figure these things out, use Solana, Ethereum, and Bitcoin, create the data, and then provide some analysis. Awesome. Wow, there it seems like there's something happening with Ethereum today. Now we have a Web3 agent that is actually able to interact with the browser with unstructured data and all these things.
Now this is basically on the data gathering side. To have a browser or an agent that is really able to interact with the blockchain itself, we have to add a bit more complexity. Yeah, sorry, I missed you. Is there an easy way to see the calls that it's doing or all the browser interaction? Yeah, we could actually enable the debug flags for this. These are the things that I pointed out. I've not enabled them, but this is, for example, here, these would actually tell you the reasoning about what tool to use and when to call what. This is really important with agents when you need to really be specific with the system prompt and do the routing and tell it exactly what to call, because otherwise it might just get confused and start to hallucinate, like saying it has this information or something. Having these debugging capabilities is essential for understanding the agent's decision-making process.
So having these hooks in here and calling out this information is really helpful for that.
Alright, so we have roughly 15 minutes left. What we have done now is our agent is interacting with coin-related market data, so it can now interact with any crypto-related web page. The beauty of that is it gets all these data points now. It gets the market, the volume, it gets sentiment, and all these things. It can actually extract everything from these pages directly without me having to connect to 30 different REST endpoints and do Twitter feeds and all these things.
Enabling Agent-to-Agent Communication for Blockchain Interactions
All right, now the last step here, which we did at the beginning, is allowing this agent to invoke other agents that specialize in a given task. The task we wanted to show you here is connecting to an agent that can actually interact with the blockchain directly, so an agent that can leverage the Key Management Service of KMS to sign a transaction and broadcast it, or just simply make read requests like RPC requests to chain. This diagram that you see here is from an architecture that a colleague of ours built, and we sort of tacked on top of this for the sake of this workshop so we can show multiple agents working together to do something. In this, he had some news source knowledge bases, a data analyst agent, and then access as well through tool calls to a crypto price API, and then lastly a tool call for accessing the chain directly. So David's going to show you the latter, interacting with the chain.
Yeah, all right, and you see this particular stack. This is the CDK that is actually also included in this crypto agents with Bedrock. So you can actually deploy it with CDK, and then there are also a couple of blockchain-related things like RPC endpoints, and these are required for this stack now. We will actually now integrate with this particular stack and then see what we can do with that. Again, it's important, I pre-deployed it because that will take a bit too much time, particularly because of knowledge bases and all these things. What I did as well is we actually updated our IAM policies because we need to have additional permissions, we need to have a Bedrock invoke agent permission for this.
And then yes, all right, now we are looking at our Strands agent again. How do we actually update it for the agent-to-agent use, or how can we now integrate it with the other crypto stack? That is fairly straightforward here. We're using Boto3 for that, and we have our own tool definition again. This is really just calling, we're doing a Bedrock agent runtime client invoke agent. We are then having agent ID, agent alias ID, and that basically tells our Strands agent to invoke, use that tool. That tool will then actually interact with our Bedrock agent.
Again, we have our tool definition here, and now it is really crucial that we are also updating our system prompt and do basically the proper routing here. So we need to tell it, okay, we have a Bedrock agent, and what is this? Everything that is, for example, for wallet operations, send, check balances, please reach out to it. This particular other stack has also some data feed gathering, so we can also use this particular agent for cryptocurrency price fetching and all these things, and we have a couple of examples in here. So for example, if I want to check my account balance, and we're talking about an account that I created, an account on an Ethereum Sepolia testnet, then it will actually invoke this tool.
Besides that, not much has changed, but I removed the browser because we're just going from tool to tool here. All right, this particular file is located in the agent-to-agent in the Agent-to-Agent communication.
So instead of using the browser, I'm now using Agent-to-Agent communication. And we will now trigger this entire build and update pipeline again. As I mentioned before, and you have seen that in the Dockerfile, the Agent ID and the Agent Alias ID are already in the Dockerfile, so this is preconfigured.
All right, it's updating. So let's see what it's doing. It's invoking the Bedrock Agent Runtime. It takes a bit until the first response. I don't even know what the specific version was. It's okay.
Integrating AWS KMS for Ethereum Transaction Signing and Wallet Management
So this other stack now has a KMS key associated with it. KMS is the Amazon Key Management Service, and KMS allows us to manage private keys. It's primarily for key management, so private keys. The beauty of KMS here is that we can actually directly integrate it with or use KMS to sign EVM transactions, specifically SECP256K1. So everything with this elliptic curve, we can use KMS for.
Oh, wouldn't be a live demo without the Service Unavailable exception. Okay, I think if you rerun it and chat with it again, it'll work. It's really throttled or something. But yeah, we are live. I mean, these things can happen. Well yeah, as I said, oh, let's see. Okay, no, there we go.
So with KMS, what we can do is actually sign blockchain transactions. Is everybody familiar with how wallets work on Ethereum, for example, or like public keys? It's important that on a blockchain like Ethereum, the accounts or wallets are basically identified by balances associated with a public address. The public address is basically just the public key of a certain private and public key pair. When we are using KMS, we can actually extract the public key, and then we have a bit of calculation. But basically, we can actually use the public key from a KMS-based private-public key pair for Ethereum, for example.
I'm not even sure if this is the right way to ask for it. That is okay. So while we're waiting for the response here, otherwise I have to do another... Okay, this is the wallet address. And I will actually go in detail now about what happened in the state, but we will first of all check what balance we have on our account.
So yeah, it's now interacting with the other agent and then basically reaching out to the RPC endpoint. Okay, that looks correct. But how do we validate that? So we're taking this particular address and we go here. This is now for everybody who has never seen it. I mean, this is the Sepolia Block Explorer. And I'm typing this one in.
And it looks like someone funded this particular address with some Sepolia testnet ETH. Awesome. Now how do these things actually work? So if you're interested in this, what happens is basically in the crypto AI agent supervisor stack, we have a Lambda function. Everything is in the index.py, and we have a couple of different functions and methods in here. I can really, if you're interested in this, I wrote a few blog posts about how you can use KMS for Ethereum, particularly with different signature standards like EIP-155 and EIP-4337 for different transaction types. But the way how you would usually do that, or how you can actually first of all map a KMS key or a KMS public key, because you do not have access to the private key. KMS is really like you create a private key, it remains inside the HSM, it cannot be exported. You can import a key, like you can, for example, import your MetaMask key into KMS, but you cannot export it. That's basically the idea. It's a fully managed key management service, and fully managed means like the backups and everything, AWS takes care of that. And the security and permissions, that's basically what you would do with IAM.
Now, as I mentioned, you have to do a little bit of calculation to extract or to do the mapping of a public key on KMS to a public address on Ethereum, for example. Here we have a method that's called calc_eth_address and we are passing the public key. This is the bytes, the byte representation of the public key. And then if you look into how keys are being handled inside HSMs, there's usually something like ASN.1 notation, so you basically need to decode some of these things. And what we have here, we are actually, the information that we are looking for is basically the subject public key, and this is what is happening here. We have the subject ASN key definition and these things are all defined in the IEEE standards on this. We are then actually extracting the public key and we are doing a bit of calculation, so we're taking the bytes, we are actually just taking the last 40 of the hex address, and then we are actually, we can turn this particular public key that we calculate into a checksum address.
And the Ethereum checksum address is basically, for everybody who is not aware of this, the upper and the lower case in the public key, this is the checksum. This is actually how you can validate if an Ethereum public key, if you want to send something, you can validate if this is a valid address or not or if something is missing. And yes, this is basically now integrating and providing all the functionality for us, and this is actually important when we are doing this get_wallet_address. The crypto agent is actually just instantiating a Boto3 client with KMS and it's basically downloading the public key, and the public key is then basically recalculated and this is then turned into our public key address.
And in the same way that we are basically mapping a KMS public key to an Ethereum wallet or to an Ethereum account, an EOA, an externally owned account, in the same way we can now also do a bit of magic for signatures. So we can use KMS to create signatures for blockchain transactions. Basically what you would do is you pre-calculate, you set the Ethereum, the EVM transaction, you take the hash value, you sign this hash basically with KMS, and then you decode it into its different components. For EVM it would usually be R, S, and V, so you have these three different parameters that are being validated, and this is actually also everything is encapsulated or everything is written down in this index.py.
All right, and now what this basically allows us to do is from our agent we can actually query our account balance. We can also go and check the account balance of other accounts if we want to, or we can ask it to send certain funds from our blockchain wallet to, for example, someone you want to send the ETH funds to or something else. So I think we're at time now. We covered a lot of ground that we wanted to, and we ended up landing on the crypto agent functionality that we hoped we'd get to, so I really appreciate your time. If you have questions about anything that we didn't get questions on during the session, we'll stick around right outside the door. Feel free to come introduce yourself to us, ask us any questions that you have, and again, enjoy the rest of the conference and have a great rest of your evening. Thank you.
; This article is entirely auto-generated using Amazon Bedrock.


































































































































Top comments (0)