In this lesson we're going to create our base email system. It's not going to have any memory yet. We're just going to set it up and get it working. All right. Let's dive in. The first thing we're going to want to do is import some environment variable. After that, we're going to start to set up our profile for this email system. The first part of this is just basic facts about the user. Like their name and some background about them. This should be a profile for the users whose email this assistant will be attempting to respond to. So you can change this to be whatever you want. Probably your name and your background. After that, we're going to define some prompt instructions. These are instructions that will get formatted into a larger prompt down below. There's two parts of this. The first is triage rules. These are parts that will go into the triage prompt. The triage prompt is what is responsible for triaging the user's email into a few different categories. There are three to be precise. Ignore, notify, and respond. And we can see here that we have instruction for what type of emails should be classified into each of these categories. A second instruction set is instructions for the main agent. This main agent gets called after we decide that we should respond to the email. So this contains instructions for what to do in that case for both the profile and the prompt instructions, these will get formatted into larger prompts down below. The reason that we're pulling them out is twofold. One, this makes it more modular and easier to see and visualize. Two in the future, some of these will actually be generated as part of memory. And so we want them to be separate from the rest of the prompt, which we are not going to update as part of memory. After that, let's define an example email. This is just to see what the schema of the emails that we'll be working with are. There's four main parts: a from email address, a to email address, a subject for that email and then the body. We'll use this to test out some of the agent parts down below. You can change this to be whatever you want. Let's now define the first part of the agent. This will be the triage step. First, we're going to set up some imports. Next, we're going to choose the model that we want to use for this triage step. We're going to use OpenAI's GPT 4o-mini model. But you can use whatever one you want. After that, we'll define the schema that we want this triage step to output. We'll use a pydantic base model here. And it will have two fields. First, will be a reasoning field. This is where the LLM can just generate some reasoning for what it decided to do. And then next, is the main part the classification step. This should be one of ignore, respond and notify. We're going to bind this type to the LLM with with structured output. This will make it so that LLM router always returns information in this schema. Now we're going to import some prompts for the triage step. There's two that we're going to be working with the system prompt, and the user prompt. Let's take a look at the system prompt. We can see here that it's got a few different sections. First, is a role section. This is where some background about who the AI should be is placed. Then we have the background on the user themselves. Then we have some instructions. This defines the three different categories of things that we want to classify emails into. And then we have a rule section. This is where we will format a lot of our instructions into. And so you can see the here that there are these little curly brackets. This is actually a prompt template. This means that there are parts of this prompt that are not filled in. And we're going to do that with different variables. And we'll see how to do that. And then finally we can see that there's a section for few shot examples. If we look at the user prompt we can see that it's much simpler. We can see that basically just formats the email into a pretty simple input. Let's test this out. We can see here that we call triage system prompt dot format. This will format the prompt template with a bunch of variables that we pass in. We use information in profile such as the full name, the name, and the user profile background to populate some things. Examples we set as none because we don't have any of these yet. And then the triage_no, triage_notify, and triage_email parts we take from the prompt instructions. We do the same with the user prompt, formatting it with information from the example email that we have. With that done, we can now call the LLM router, which is this LLM with the router schema attached. We pass in two messages a system message with a system prompt as content, and then a user message with the user prompt as content. If we take a look at what result is, we can see that there's two parts. There's a reasoning string, this is the logic of the LLM. And then there's a classification of the LLM. In this case it's saying to respond. Now's a good time to pause and try it out with some different emails or different instructions and see what you got. With the logic of the triage, step out of the way. We're now going to tackle the main agent. First, we're going to define some tools. So we're going to import the tool wrapper from LangChain. The first tool we're going to define is a tool for writing emails. This tool will take in three things. An email address to send the email to, a subject of the email, and the content of the email. Right here we just have a fake dummy tool. So we're not actually implement in any logic in it. In the real world, you'll connect this to your Gmail API or outlook API to actually send the email, but here we're just going to mock it out. The next tool is a schedule meeting tool. This is going to take in a list of attendees, a subject, a duration, and a preferred day, and it will schedule a calendar meeting. Again, this is just a mock tool for now. In the real world you would connect this to real APIs. And the final tool we're going to define is a tool that will check the calendar availability. So we'll take in a day and it will return the availability for the user on that day. Again, we're just mocking this tool out. So we're always going to return 9 a.m., 2 p.m. and 4 p.m.. With our tools defined, we're now going to go ahead and create the prompt for this agent. So this is actually going to be a function that takes in the state of the agent and returns a list of messages. This list of messages is going to consist of two parts. One will be the messages already in the state. And then the second will be a system message that we put at the start. What exactly is in this system message? If we print out the prompt, we can see that there is a little bit about the role that the AI is taking on. There's then a section that lists out the tools that it has access to. And then there's a section for the custom instructions. And we're going to pull these in from the prompt instructions that we defined above. Let's now build the agent. We're going to use Create React agent which is an off the shelf agent implementation. We're going to create this agent by calling Create React agent and passing in three things. First is a string corresponding to the model to use. In this case we're going to use OpenAI and the GPT 4o model. Next we're going to pass in a list of tools. In this case the three tools we have defined above. And then finally we're going to pass in the prompt. In this case, the function for creating the prompt that we have defined above. We can now try it out. So we're going to invoke it with the list of messages. And in this case let's pass in something like "what's my availability for Tuesday?" We'll get back a response. This response will have a list of messages as part of the state. If we print out the last message in this list of messages, we can see that it responds with: "You have the following available time slots on Tuesday 9 a.m., 2 p.m., and 4 p.m." Great. If you remember, these are the times that we hard coded our calendar tool to say that we were available. Let's now put it all together and create the overall agent. The first thing we're going to do is define the state of the agent. Here, the state is going to consist of two parts. First is an email input. This is what the user will pass in. This will contain all the information about the email. Second will be a list of messages. This is where the agent will do its work. After defining the state, let's import some things that we'll use to build the rest of the agent. We're going to first define a node for doing the triage step. So this is going to take in the state of the agent and it's going to return a command. A command is going to say two things. And we'll see this later on. But it will say two things. It will return an update to the state and then it will say where to go. And so these two values here are possible values of where to go after this triage node. We could either go to the response agent or we could go to the end of the graph. This is going to depend on the result of the triage step. So let's actually implement this logic. The first thing we're going to do is pull apart the email and put into a few different things that we're going to pass into the prompt down below. This is just done for convenience. There's no real logic here. Next, we're going to create the system prompt. This is the same as above. After that we're going to create the user prompt. This is using the author, to, and subject an email thread information from the email input. We're then going to call the LLM router that we have defined above. Make sure this is LLM router not LLM. This is the one with the output that will have the classification schema. We're then going to handle the three different types of classification that can occur. Respond, ignore and notify. If it's something else we're going to raise a value here that's unexpected. And at the end we're going to return this command. This basically tells the graph which node to go to and which update to apply. So each of these branches for each of these classification results should set a go-to value. And an update value. Let's take a look at respond. This is what happens when we want to respond to the email. First we're going to print out some nice stuff. This is just so that we can see what's going on. Our go-to is going to be response agent. So we want to go to the response agent afterwards. The update we're going to apply is we're going to add a new message to this list of messages. It's going to be a user message. And it's going to have this content respond to the email. And then it's going to paste in the email input there. When the LLM calls ignore we're first going to print out something. This is similarly just for logging. Our update is going to be none. So we're not going to update the state at all. And then we're going to call go to. We're going to go to the end node. What if it's notify? Here for mocking. It's actually going to be pretty similar to ignore. We're going to print something out with a slightly different print statement. And then we're still going to apply no update. And we're going to go to the end of the graph. In real life this would probably do something else. This would go to some sort of notification system. So you might want to go to a different node if you add that into the graph. But here we don't have that. So we're just going to do a simple go to the end. And that completes our triage node. Pretty complex. But hopefully you understand. At a high level it's basically formatting a prompt calling the LLM. And then based on the output deciding which node to go to next. Let's put it all together and define our email agent. So we're going to use state graph which is an agent that operates on a particular state. The state that it's going to operate is on the state that we defined above. So it has an email and a list of messages. We're going to add two nodes. The triage node which we defined above. And then the response agent which is a sub agent. This is the react agent that we first defined. We're going to add an edge from start to the triage router. This is basically just saying that the first node we want to go into after the start is this triage step. And then we're going to compile this agent. Before using it, let's check out what it looks like. So we can use this draw mermaid PNG method on the line graph object to get a nice mermaid drawing of what it looks like. And we're going to pass this x ray equals true. This is just allowing us to zoom in to this response agent. Because this is a sub agent in itself. So we want to visualize it. So if we look at the graph we can see that we first go to this triage step. From there either goes to end or it goes into the response agent. This response agent is of course an agent itself. It's got this nice little react loop here of an LLM, calling something and then calling some tools and then going back, or it can finish. Let's try it out on a few emails. So, first here's one that looks like some spam. It's spamming some nice sales email. Hopefully this will be ignored by the email agent. Let's call it with this email input and we can see that it prints out this classification Ignore. So here we can tell that it's successfully ignoring this email. Let's try out another example. This time one that expects a response. If we call it we can see that we print out this classification respond. This means that we're getting a response. But what exactly is happening? In order to see that, let's take a look at the list of messages. First, we can see the human message. This is the human message that the triage node puts in to the list of messages. We can then see that it calls the right email tool. In here it responds to Alice thanking her for reaching out. We can then see that there's a tool message basically just saying that we sent this message. And then we can see a final AI message saying, I've responded to Alice's email. Blah blah blah. This is the complete email agent in action. It first triages the email and then it handles it accordingly if it's meant to. Now's a good time to pause and try out some other emails. Try out some other instructions. Try out messing around with the system prompt and things like that. This concludes building the email agent, but it still doesn't have any memory. And so that's what we're going to add in in the next lessons.