Hello everyone, thank you all for joining us today. My name is Kevin, I'm an engineer here at Anthropic and today we'll be learning about how to build agents that remember. So today, we're going to talk a little bit about the base case with agents today, which is that they're isolated. And this kind of limits their usefulness in a lot of real world workflows. We'll look at how we can actually solve this problem with our new agent memory stores feature that we've launched. This will give agents access to a live memory store that they can read and write to over multiple sessions. And then we'll look at how we can improve these memory stores over time using a new feature that we call Dreaming. And then finally, we'll get to see how all of this ties together with both our CLI and also our awesome console interface. So in the previous workshops, I think we've learned a little bit about how Cloud Manage Agents has these concepts called an agent, environment, and a session. In this workshop, we're going to add two additional concepts here. The first one here is a memory store. So a memory store is a persistent file system like store that attaches as a resource to sessions that you create. And it gives agents the ability to read and write information across sessions. A dream is what is a asynchronous job that runs in the background. It looks over an input memory store and a bunch of your previous sessions that are represented as transcripts. And then we run a harness over them to distill new information that maybe the original agents missed. We do things like fact checking. We also organize a consolidate and to duplicate information so that your memory stores don't grow unbounded over time. So also in case anyone in this room has not already downloaded the workshop repository you'll need for this, here is the URL. I'll give a few seconds for folks to just grab that. OK, so let's talk a little bit about the problem today. So when you create agents on Cloud Management today and sessions, most of the time you're creating one session at a time, and these are isolated. The agent doesn't remember information from the past, and it doesn't transfer information to future sessions. So I want to take us through this base case today. So if I switch over to my computer, I'm in our workshop repository here. Hopefully everyone can see this in the back. But I've just run the Bootstrap script that we've included in the repository. And what this has done is basically created some seed information for us. So we have an agent. We have an environment. And we have a few previous sessions that talk about things like the keynotes from day one, as well as a previous workshop. And so what I'm going to do from here is actually go ahead and start walking through this guide with you guys. Feel free to follow along your computers. I'll be using the CLI, and then also showing kind of the console interface for each of these steps. So first, we're going to create a session that basically tells it some new information. So I'm going to copy this command here. And as you can see, we are creating a session with the agents that we've created before, with the environment ID. And we've given it a title here of just like, write test with no memory. Great. So now that we've created this session, I'm going to quickly switch over to my console here. And you'll see that, let me just move this over. You'll see that the session shows up in console. It has a status of idle, nothing running yet. So then we're going to switch back. And then I'm going to send this session some new information. So once I copy this. And what I'm doing here is sending a first user message here with information about the CMA talk yesterday, naming a few keywords like multiagent orchestration, multiagent orchestration outcomes and memory. And I've also just given it this URL example that I took notes and uploaded them here. So if I switch back over to my console, we should see this event pop up. And what we sort of expect the agent or the model will do here is it'll just respond and say, like, great. Thanks for the information. Not sure what else you want me to do here. So we'll give it a sec and maybe focus the catch up. Let's get a little refresh. Sorry. Yeah, so it looks like the model responded here. Just collapsed this. Yeah, it's basically saying, OK, great. Thanks for telling me this information. So then if we go, sorry. This is using, I believe, Sonnet, the agent that was created. at the beginning. Cool, so if I go back here to my workshop here, we're gonna create basically a second section that's kind of the retest. So I'll go through these steps a little bit faster. And then again, I'll send it a message here that's this time, I'm gonna ask it for information about the stuff that I just told it. And if I go back to our console here and check out the other session that should have been created, we would expect the agent to basically say something like, yeah, I don't really have access to information. I can help you in these various ways. Great. So that's effectively the base case today. So if I go back to the slides real quick, this is a quick recap of what we did. We told it something, asked another session about it later. No information is transferred between the sessions. So how do we solve this problem? Just like in humans, we've introduced the sort of concept of memory. And again, a memory store here in the Cloud Managed Agents platform is a file system like Store. Under the hood, you can create as many memory stores as you like here. So you don't have to necessarily restrict a memory store to one organization. You could create it per user, per workspace, et cetera. It's up to you to define what the boundaries of the memory store are. And then under the hood, this memory store gets attached as a file system to the session container. And the model has tools to read and write to it. The actual interesting thing here is that we've actually mounted it as a file system because it's such a powerful interface for the model. You can use things like bash to explore the file system. It can use grep to search for keywords. It can also read files and do a bunch of really powerful things that make it much more useful for the agent. So I'll switch back to my computer here, and we'll walk through how to create a memory store. So first thing first is actually creating it. So I'm going to copy this command here. Feel free, again, to follow along on your computers. And the kind of parameters that you need here are mainly just like a name. So I'm calling mine CWC memory. You can give it a quick description. And then I'll show you also in console later that there are two additional parameters that you can set here. But let me just follow through with a simple example. Once I create this memory store, you can actually see it in console under manage agents, memory stores. And you'll see that it's active. You can actually click into it and view, essentially, a file system viewer of what's currently in it. Of course, there's nothing in it right now. Additionally, we offer functionality. We offer the ability for you to manually add memories. So you can create a file on your specific path, add some content, et cetera. If I go back just a brief second and talk about creating a new memory store, there's actually two additional parameters that you can set on the memory store when we actually mount it. So if I go back to the repository here, The next step, once you create a memory store, is to actually use it with your sessions. So I'm going to, again, copy a few of these commands. So the first one here is basically just giving us the shape that we need to pass the sessions API request. I'll paste it in our terminal here so we can see it better. So again, the memory store here, you just pass in a memory store ID. And you can also give it a prompt around that will steer the agent to read and write specific information. So you might want it to focus on maybe a specific link or a specific area of focus on, let's say you're making like an investment agent, right? And you want to focus on specific things to remember for the future. So you can do that with a prompt parameter. Additionally, there is an access field that defaults to read or write. You can change that to read only, which will make it so that the session and the agent will only be able to read from that memory store, cannot update it. So once I run this, you'll see I have created a new session in console. And this time, it'll have a memory store attached. And then if I send an event here this time, we'll just basically repeat the test that we did just before. So let me grab this. Again, same text as before, we're telling it new information. Hopefully, we'll be able to observe a different behavior this time. Yeah, so if you click into the session details, you'll see the information that I just gave it. And now the model is first looking at memory to see, OK, was there anything that I need to remember for this conversation? And now it's going to actually like, of course, there's nothing in our memory store. So now what's going to do is actually save the content that I told it to that member store directly. And it saved it under this sessions.md file. And it's great telling me that what it did. So then if I go back and do that same test that we did before, this time I'll just copy both. Sorry. Again, this time we're gonna create a new session with the same memory store that we were just using. And we will send it an event here asking at what are the things that it found or learned from the CMA talk. Once again, going back to our console UI, we can see the recall test running. And as we would expect, the model is now first looking at its memory store to see if there's any information. And again, it's now using grep to find any sort of key words here. It's looking for CMA. And great, it found a lot of information that we just told it from a previous session. And now it's able to answer my question. And this is, of course, a very simple example, but this illustrates the power of memory. And this is something that was kind of difficult to do before. Right? I'll give a quick pause in case anyone's straggling. OK, great. So what else can you do with a memory store here? Well, we actually offer additional endpoints that allow you to manually inspect the store itself. So I'll use the CLI here. But for instance, you can list all of the memory files that are in the memory store. We can do that. There's also each memory files in a memory store are also versioned. So anytime you make a change to a file, et cetera, there's a new version that's created and we offer a set of endpoints for that. And then I can also kind of take you through the memory store UI. So each memory store you create, again, is here. And if we go back to our file system view, you can actually see the files that it created. There will be a directory structure here if Claude is creating subdirectories to organize memory files. You can actually edit these memory files directly if you wanted to. So for instance, if Claude wrote something that was incorrect, or maybe you just wanted to add more information, you can do that. And again, as we saw before, you can add additional memories to a memory store. OK. So I'm going to go back to the slides real quick. And as we just talked about, this is how you create a memory store and then mount it on a session that you want to use it on. Again, it's up to you to decide which of your sessions will use memory, which ones will not. We also saw how you can list memories and see what's currently in a memory store. And let's move on to talk a little bit about Dreamy Now. So when you have agents that are reading and writing to this memory store over time, we've noticed that oftentimes they can start just dumping information to that memory store. So it'll start writing maybe every task that you ask it to do, it'll maybe record its information. And over time, your memory store is going to grow. And there's no real process before that would allow you to sort of organize that memory, maybe check to see if anything was stale, and consolidate any duplicates. And so this is where Dreaming comes in. Dreaming is a batch process that runs, again, asynchronously. You launch it using our API or through console. And it'll run a new Dreaming Hardness that we've built that is a multi-agent setup. It will look over each of the input sessions that you've given it. So you specify an input memory store that you wanted to dream over, along with a group of transcripts that you think might help or enrich that memory store. It'll look through each one, do, again, fact checking, enriching with additional details, maybe dates, specific identifiers. And then it will also organize those memory files and see if there's any duplicates, anything that can help fix so that when you produce an output memory store such that in the future, when you attach that output to additional sessions, it will hopefully increase efficiency, an efficiency of information retrieval, and also hopefully increase the intelligence of the agent. So let's take a look at how this works. Again, switch back to my computer, and we'll walk through it together. So to get started with dreaming, basically, you'll need to actually create the dream job. And I'll go through a little bit of the parameters here. So the model here that we're choosing is Cloud Opus 4.7. You can choose between Opus 4.7 or Sonnet 4.6, depending on the level of quality you want, as well as maybe token costs. It takes in two inputs. So you'll need the memory store that you want it to dream over, as well as a list of session IDs. So this is up to you to decide. You can maybe dream over daily and dream over maybe 10 sessions at a time or 20. They could go all the way up to like 100. We're also looking to scale it further. Yeah, that. Optionally, you can also provide the Dream Job some additional instructions that you might add. So we provide it with a default prompt that does a bunch of things. If you wanted Dreaming to, for instance, specifically fix a few things, like maybe you're working in a domain that requires very specific details, right? You might ask a Dream Job to really focus on, hey, make sure you backfill these details so I remember for the future, right? You can also get it to, You can also steer it to maybe organize files a bit more. Like, I want this specific structure in my memory store. Please do that. So let's actually go and run this command here. Great. We'll get back a dream ID. And then, once again, I'll go back to our console here. And so dreams are under, again, manage agents, dreams. And once I create the dream job, it'll start with pending, but it'll start running pretty shortly after. And you can actually see the status of the job both in console through the API. I'll show both. But in console here, you'll see the input memory store, as well as a token count. And generally, a dream job can take, depending on the size or the number of transcripts that you give it, it could take anywhere from a couple minutes to hours at a time. And that's really the benefit of doing it asynchronously. This is not something that you want to do live while your agents are working. We'll just give it a minute here to run. And you can see, as it's running, as the agents, or as the harness itself is running, we're updating the token count for you, so you can track its progress over time. The other really cool thing here is that Dreaming is actually built directly on top of Cloud Management agents primitives. So you can actually see that we are creating a session for the Dream job itself. And you can actually click into it to see exactly what the Dream is doing. This offers a really nice amount of observability, and so you can diagnose issues potentially. And so you can see the prompt that we give it. There's a lot of details here that you can explore on your own time. But under the hood, the dreaming harness itself is launching subagents to look over all of the transits that you've given it. And each subagent essentially has a system prompt that tells it what to do, look over it. And the orchestrator is responsible for just like making sure all the agents are running and kicking them off as they go. So we'll give it another minute to let this run. And another thing to call out here is that while we don't actually touch the input memory store at all that you create. So this is a non-destructive process. What we actually do is we will clone your input memory store into what's called an output memory store. And the dream job will be writing basically to a new memory store, such that any edits that are made are non-destructive. And then we'll see down the line how you can utilize this output memory store in your future sessions. Generally, this takes about a minute or so, depending on how fast the job runs. So, one of the things is that you'll see that I'm sort of checking on the job periodically as it's running in console. When you do this programmatically, we offer an API that allows you to just essentially query for the dream job and it will have a status so you can pull for the status. Great. So, it looks like it just completed. The cool thing here is that in console, we actually show you a diff of what it did. So you can see, Dreaming here, it created an index file. This index file has sort of these slugs that reference the various memory files that a future agent might need. And the main goal of this is really just that future agents, it's a lot more efficient to kind of look at an index file and quickly grok what it needs to go look for instead of maybe doing a wider grep. Additionally, it's actually adding like additional information that was not present in the first couple of sessions that I created. So it's creating this event logistics file. It gives the whole schedule of code with Claude, a bunch of names as well. And again, schedule for day two. And you also see that it actually kind of reformatted the memory file that I created in a previous session. So this time it is adding, again, a slug, a description of the event, some additional metadata, and again, adding more details. And generally, we find that more information actually really does help future sessions. And if you think about intuitively, while an agent is working on a task currently, it's kind of hard to predict down the line what it might need. That's just generally a harder prediction problem. So it's actually good to kind of write additional details down that a future agent might remember. And dreaming can always go back and remove stuff that is no longer needed. And if I go to the output memory store here, I'll just click on it. Again, you can see all the files that I created. It's another good way to sort of see what's going, what Dreaming did. And if you wanted like a human in the loop kind of review process, this is kind of where this is super helpful. Human can kind of go in and see if the dreaming hardest made any mistakes. Okay, great. Just gonna switch back to the slides real quick, I want to show a diagram. Yeah. So again, under the hood, this is sort of how dreaming works. This is a multi-agent harness. We have an orchestrator that is mainly responsible for spinning up subagents. And again, we spawn one subagent per input session that you give it. And the reasons behind this are we actually kind of want dreaming to be exhaustive by design. If you give it 100 trans, you want to make sure like Claude is looking over all the information to make sure it's not missing anything, right? Great, so now let me switch back to my computer again. And this time I'm going to actually like walk through how we might use this in a future session. So once the dream is done, you can actually go and grab the output memory store using this. So again, we're just retrieving the dream resource with the dream ID that we created and then querying or just grabbing the JSON memory store ID. Great. So this is the memory store. And again, you can look through what memories it created. And now we'll do this sort of test again that we did before with the two sessions. So I will create a new session here. And you'll notice that this is now are using the output memory store from Dreaming. Once again, we'll send it in events here. We're just asking it what sessions I attended, what resources do I have links for, and what follow ups I flag. Once again, going back to the console, it's really a great way to visualize what's going on here. And you'll see that this time when it's reading from memory, you'll see all the stuff that dreaming did. Right? So the index, the event logistics. And it's now starting to read the index first. OK, great. Now knows I'm going to go straight to the sessions file. It's being a little exhaustive here, just checking for event logistics. Okay, great. Let's see what it came up with. So, these you can see, I'd have to go back and show you the previous session. But this time, I think there's a lot more information here. So, it gave me a recap of all the sessions I attended. It's giving me time stamps now about all the sessions that were planned for day two, as well as the resource links. I think this showcases again how dreaming can really enrich information that is transferred between sessions. And then optionally, at the end, if you're really happy with the output memory store here, you can go ahead and actually retire the old memory store. So this won't affect your previous sessions. It just means that it will keep you the number of memory stores in your organization down to a reasonable level. Great. So I'm going to switch back to the slides here. And talk a little bit how you can view sessions, memory stores, and dreaming as three composable layers here. If you think of a session as an isolated instance of an agent running, it's usually typically one conversation thread, typically ephemeral. A memory store augments that. So now you can connect information between your sessions across multiple sessions, right? And then finally, with dreaming, you're now organizing, enriching, and improving your memory stores over time so that as you scale up the number of sessions you have, as you scale up the information that it's being processed through those sessions, your memory stays at a reasonable level, it's manageable, it doesn't blow up. Also, it checks for things like staleness to make sure all the information is up to date, right? I wanted to highlight some of the maybe good questions that I got from the audience here. So one of them was around generally like sort of what is the token usage of this feature like. So as I said before, I think by design, we actually do want it to be exhaustive. So we do expect it to use a lot of tokens. The nice thing here is that because most of the processing is agentic, most of the tokens are actually cash. So we're expecting about a 95% cash rate on most dream sessions. And additionally, we are exploring other ways of offering this at lower costs to you. So example of this would be similar to our batch API, we could offer things at a 50% discount by scheduling at a different times. Other additional token usage controls include switching the model, steering the prompt a little bit more, also providing more general budgeting of tokens. So I think we're just about winding down. So I'm going to quickly kind of go over again for the folks remaining in the room, like what we went over today. So again, we talked about the problem that most agents face today, which is like, how do you remember information across sessions? I think this is a pretty well-established kind of problem now. And we talked about how memory is the first step to addressing this. You give agents access to something where they can dump the information, read from it, et cetera. But we also saw how this creates a problem where memory stores can grow unbounded over time. They can grow disorganized. Information can grow stale, et cetera. And then we saw how dreaming can be used as a way to mitigate this problem. So we take another set of agents that their entire job is to improve that memory store for future use. And with that, I'd like to thank everyone for coming to today's workshop. Hopefully it was helpful, and hopefully by the end you'll learn how to, or you'll know how to integrate memory into your own use cases.