Back to all workshops

Build Agentic Workflows with Mastra

April 3, 20254:00 PM UTC1 hour

2025 has seen AI agents evolve rapidly, but orchestrating complex AI operations remains a challenge. This session is your chance to master Mastra's workflow system and create sophisticated, multi-step AI processes that actually work in production.

Workflows in Mastra help you orchestrate complex sequences of operations with powerful features like branching, parallel execution, and state management. The Mastra team will show you how to build resilient, observable AI workflows in less than an hour.

Use workflows to create systems like a content generation pipeline that coordinates research, writing, and editing steps. Or design an AI recruiting workflow that gracefully handles user input, database lookups, and external API calls while maintaining context throughout the process.

This event is open to all devs and aspiring AI engineers, regardless of background, so feel free to share the invite link. You should be comfortable with basic JavaScript and the command line.

Workshop Transcript

1:07

Hey everybody, thanks for joining early. We'll probably start a few minutes after the hour, so we'll get started here in a little bit. Hey, good afternoon. Good morning.

1:43

Good morning. Yeah, we'll get started here in just a little bit. I just like just want to ask like is there something in between we can ask the questions or what's the flow that you're going to take it out? Yeah. So, we'll we'll save time. You feel free to ask questions along the way and we'll

2:01

try to answer them in the chat, but there'll also be time at the end for some Q&A. That's wonderful. Thank you.

4:14

All right, we'll probably wait about two more minutes because a few people will probably be funneling in here a little late. But, you know, while we're waiting, if you want to drop in where you're where you're calling in from in the chat, that's always kind of fun. I am currently in Sou Falls, South Dakota.

4:51

We got Iceland, Japan, Berlin, Norway, LA and San Francisco, New York, the Boston, a lot of the a lot of the staples of of the United States for sure, but a lot of uh a lot of from from all over, which is school. And also before we get started, if you haven't uh if you do have questions and we'll I'll mention this again at the end. If you haven't joined our Discord yet, uh you can find it in

5:30

the the footer of the website or on the top of the docs site. It's a great place to go if you do have questions, if you are experimenting with MRA, trying to build out workflows. So, I'll mention that again, you know, at the end. But

5:43

for those those of you here early, if you do want to uh jump into the Discord, it's a great place. Everyone on the team's there. You know, we have pretty vibrant community that'll also try to answer questions. So, it's a great a

5:55

great place to hang out. We'll wait about 60 more seconds and then we will kick it off. Okay. Well, we will go ahead and get started. I will share my screen. Yeah.

6:38

Lucky for you all attending or, you know, watching the recording. It's you don't just get me today. So, you know, Tony is also here and he's going to be uh doing some of the hands-on pieces of our of our workshop. So, we you get both

6:50

of us today. So, let me share my screen and we will get going. And we, you know, if you do have questions along the way, I'll encourage you to ask them in the chat. We'll try to get uh answer

7:04

a lot of them as we go if we can, but it's also possible that if we don't get to it, you know, there'll be time at the end. feel free to ask it again if we didn't get your question answered. So, let's go ahead and get started. All right, we're going to try sharing the desktop. Hopefully, you all see this. And if all goes well, you

7:30

should see a slide that tells you mpm create master. So, if no one stops me, I'm assuming in the I'm in the right place. So let's talk a little bit about the workshop goal. We're going to talk about agentic workflows, how to build

7:43

them with MRA, but we're going to spend a little time at the beginning before we dive into the code just talking about why agentic workflows even exist, why do they need to exist? Because it's actually one of the most common questions we have from people is why do I need workflows? You know, how does this compare to just having an agent or an LLM make decisions? And so I think

8:03

spending a little time talking through the problem might be helpful for some of you that are getting into this and you're not quite sure when should I use a workflow, when should I use an agent, you know, should I use a multi- aent network? There there's all these different things that uh you have to get into and it really kind of controls like

8:19

the decision-m process of your AI applications. So we're going to talk about uh like I said agented workflows. We'll do uh quite a bit of demoing. So we have quite a few examples. We will share the code

8:32

afterwards. So just know that you know it's going to be in a public GitHub repo. You can download it, play around with it. The uh this is getting recorded. So you'll also get a recording

8:43

of this. It usually takes a few hours before I click the send button. So you know, don't worry. It it'll end up in

8:48

your inbox, but it might take a few hours. And then we'll have time at the end for Q&A. So a little bit about who we are. So my name is Shane. I'm one of the founders and the chief product officer of Mastra. I was in and product

9:02

at Gatsby and Netlefi. I built a service called audio feed and I've been in the open source world since I first uh built the Drupal module and published it probably 15 over 15 years ago, but not to date myself. And yeah, reach out to me on Twitter or LinkedIn. Let's connect. And

9:20

I'm excited to introduce Tony and he's going to he'll take over here in a little bit. So, uh Tonyy's one of the founding engineers of MSRA. He was a co-founder of uh Zeitz Zit. I don't know

9:31

Tony how to pronounce that but maybe that's why you all changed the name. Uh and then uh yeah CTO of token terminal before he joined us at Astra. He was one of the co-authors of Nex.js and he's

9:44

kind of our workflows and cloud expert and so yeah definitely connect with Tony as well. So you there's a big problem when you're building you know agentic applications or AI powered applications. It's like it's kind of the decision problem. Who are you leaving

10:04

the decisions up to? Are you making the decisions? Are you letting an LLM kind of guide the decision-m process? The problem is as we've probably all seen is you don't always get the same results every time. And

10:15

depending on, you know, how someone maybe asks a question or or what they're doing in your application, the results aren't always as accurate as you want them to be. And so there's always this balance between flexibility and reliability. And so as developers, sometimes we just need more control. So although LM have really

10:35

improved quite a bit, they still struggle when you have really complex decision-making trees, when you have to follow multi-step processes. uh reliably when you need to you know maintain context over many steps and you want to make sure that you have the consistent execution every single time. You know, I

10:53

was talking to um some some of our friends at a company called AOR and they're talking about really voice voice agents and they they do a lot of evaluation and uh kind of replayability and observability on voice agents and they say one of the things that they struggle with the most is helping teams that if the person talking to the voice agent follows the script and answers the questions, it actually works very

11:18

reliably. But as soon as they maybe ask some kind of side question or go off it off, you know, the LLM often has time picking back up where it left off. So there are still states that you can get into where the LM doesn't always make the right decision.

11:37

And so let's talk a little bit about why workflows matter. They're a little bit more deterministic, so they have higher reliability, a more clear execution path, makes it easier to debug. It's a more structured process so it's easier to maintain. You can kind of have these human in the loop capabilities which allow you to kind of add guard rails and

11:53

like safety mechanisms and also just you know make them interactive. And then you have a little bit more fine grain control. So there's a lot of reasons why you know workflows in general are uh helpful in this regard. and of and I couldn't uh do an

12:09

you know maybe this uh image style is now been dated by a week but when I was putting the slides together I couldn't help but uh include some images. So I I like to always think of this as like a crawl walk run of AI applications. So there's kind of like what we think of today at least as we know there's kind of like three stages of of decision-

12:27

making in AI applications. So the crawl approach is you kind of control the decision- making with workflows. The walk is more agent-driven decision- making and you maybe have tools and maybe some kind of reasoning loops that allow you to have a little bit you kind of turn over more control of decision-m to an LLM. And then the run is much more complex multi- aent

12:51

systems where you know maybe there's an LLM orchestrator that talks to other agents. And at Maestro, we we need to support all three of these things because depending on the complexity of your application, you might need to use one or maybe all of these depending on what you're building. So it kind of goes, you know,

13:11

from left to right from less determin or more deterministic to more probabilistic, right? And so with workflows, we or with MRA, we kind of have three primitives that fit into these categories. We have workflows which we're going to talk a lot about today. We have agents and we have agent network which is in kind of an

13:30

experimental state now but it is coming because ultimately uh you know that's what everyone wants. This is the dream. The dream is you have this agent network. You can just ask it a question and it calls all the agents it needs and

13:44

it just makes the right decisions for you 100% of the time without failing. But this is the reality. This is probably where we're at. You know, now I would also, you know, argue that

13:56

the line moves a little bit depending on your use case. If you are uh writing having it write code that gets reviewed by a human, maybe we're, you know, further right. If you're uh having it make medical diagnosis decisions, maybe we're even further left, right? So, it does depend, but just kind of roughly

14:14

speaking, we're kind of in the the middle of where you can use workflows, you can use agents. Depending on the situation, you might use one or both. And we're kind of, you know, moving towards this dream of as LLMs continue to get better, as the tooling gets better, we'll have this kind of agent network where uh your agents just do can

14:32

can do it all for you. So, there is a little bit of this kind of challenge of choice because we have these different primitives and that's why we really wanted to have this workshop because it's often difficult. You know, we talk to customers in our discord. We we have calls with them almost every day. uh just people using our open source

14:51

product, people trying our cloud platform and it's often difficult to know where to start. So some teams they want to start with more control. So they start with workflows and they over time they maybe evolve and say well maybe an agent could do this part or maybe we need it to be more free flow and flexible so we'll try to use an agent here. And then some teams start with

15:10

agents or you know some even try to start with agent networks and then they quickly realize that there are parts of it that just aren't working well. And so they need to you know maybe pull parts of that application or parts of that process out into more deterministic workflows. And sometimes they end up with a balance of a little bit of

15:26

both. And so I want to use an example here of kind of a customer success engineer. Imagine you're hiring a customer success engineer for a company.

15:38

When they start the first day, you give them a bunch of tools. Maybe it's Slack, maybe it's notion, maybe it's Zenesk or some kind of ticketing software, but then you also give them a set of playbooks or runbooks or checklists depending on how sophisticated you are as a company. Like the more sophisticated companies have pretty well- definfined processes,

15:57

right? But ultimately that customer success engineer is following those procedures, but they have to use their judgment. And so in this scenario, I always like to think, well, the engineer is kind of like the agent in the MRO world. The playbooks are the workflows. So oftent times we see uh customers that

16:15

want to build an agent that maybe has flexibility, but it calls discrete workflows as tools that are a little bit more uh deterministic when you need to do certain things. So for a customer success engineer, maybe if a support ticket comes in, they run a specific playbook. And maybe if there's just a, you know, a chat interface there, it's

16:34

more open-ended and the the agents actually making those decisions, but it can call different uh procedures or playbooks when uh it's actually needed. And so there's a nice blend of both of these things because as I mentioned before, higher performing teams typically have better documented process. So, why would agents be any different if you just if if you were to have a customer success

16:56

engineer come on day one and you just gave them one big document with a whole bunch of information and said, "Here's your here here's everything you need." If the more detailed it is or the more broken out and structured it is, the better they're probably going to be able to uh at least maintain your standards,

17:10

whatever those standards are. And so, the the agents are the same same way, right? An LLM is the same. The more

17:15

information you give them, the more uh you can break down the problem into smaller problems, more discreet steps. the higher they're going to be able to perform, the better they're going to be able to maintain your standards. Uh let's see. Yeah. Okay. And I always like to use the smart

17:38

eager intern analogy. I think the state of LLMs today is like you have a really smart, eager intern that wants to please you and they're going going to try to tell you the things that you want to hear and they're going to try to help you out as much as they can, but they're not always going to be able to do things 100% accurately. And if you look at them

17:55

in that light, then you can kind of see why having these like quote unquote playbooks or these workflows can become uh useful because you kind of can help guide them in in the right directions. So let's talk a little bit about Maestra before we jump into some code. So MRA is an open source AI agent framework for TypeScript. You know, we have agents

18:15

with tools, memory, tracing. We have state machine based workflows that have human in the loop. And we try to keep a really simple API. That's what we're talking about a lot today. We have a whole eval framework. We have, you know,

18:27

storage for rag pipelines, local development playground, and a whole bunch of other things. But MRA workflows are are kind of core principle when we started. Uh so Sam had kind of had this quote one day when we were talking. He's like he said you know you should not have to learn graph theory to just build an a aentic workflow. So it should be simpler than

18:46

that. So our approach is a simple intuitive API really to have like code driven definition so you have more control and then but visual feedback in the playground so you can see because workflows are still a visual thing. So, we want to provide kind of the best of both worlds. And this is uh from our website. And so, you'll notice some of the, you

19:06

know, some of the quality issues maybe with some of the lettering on a few things if you read too closely. But the idea is you kind of get this workflow graph with this, you know, step then after. And this makes it really easy to get started with our our workflows. And so, we'll talk through this. When you do get more complex, it does get

19:26

challenging whether you're using a you know a graph theory approach or whether you're using this to really uh comprehend really complex workflows. If you've ever seen you know there are some like visual workflow tools and if you ever seen someone really complex workflow that you it's very difficult to

19:40

follow unless you really dive in and take it step by step. When you're writing workflows in code, it can get that way as well. But we do want to have this clear control flow. We want to have the ability to sus suspend and resume.

19:52

And we are, you know, we're built on top of XATE. So it is a state machine. We can store the state. We can resume the

19:57

state. And it makes it really easy for us to, you know, have a flexible way to really build a a it's a nice API on top of what's under the hood ends up being a state machine. So we're about 15 minutes in. A

20:12

good time to hand it over and actually start looking at some code. So Tony, if you're there, I'm going to hand it over to you to walk us through some examples. I am indeed. Thanks for the intro,

20:24

Shane. Let me just quickly share my screen here. Everybody should see cursor.

20:31

Hopefully, no one's no one's saying they don't. So, that's a good sign. We do. We do. It looks

20:37

perfect. Um, so I have six examples in total prepared for you guys today. Let's start with something real simple. And,

20:47

um, let me see if I can zoom this in a little bit. You guys see pretty well now. All right. So, let's start by running must for dev to get our development environment

21:00

running and open up development here on the browser. Open up our first example. Okay. So, the first workflow we're going to be looking at today is a two-step sequential workflow where the

21:14

first thing we're going to do is fetch the weather forecast for a given city. So the workflow itself has a parameter city you pass in the first step uses that city fetching the weather and then it use an LLM to plan some activities for that city uh and that given weather. Let's have a look at the code here. As

21:32

you might see here, first we do this step, then we do another one in code looks very similar. We have a weather workflow that takes as an argument a city that's of type string. The first step we do is fetching the weather and then so sequentially after this is completed we plan some activities. If we wanted to add a third step we could do simply something like that but then send

21:57

an email. Now what these steps look like individually fetch weather being the first step. We have a description which shows up here in our user interface as well.

22:11

We have the name which is kind of the ID here. We specify an output which is um the actual forecast. The type looks like this. So we have a date, some temperature information, chance of rain

22:25

condition and the location. Um and what the step does is it first first accesses the actual like input of the workflow. In this case being an object with city string. Um

22:38

this comes from context. context is like a thing that's passed into all the steps that has um all the runtime contextual information like the input of the workflow in this case but also as we'll see later on um outputs of previous steps that we've executed. So what we do with this city is we use like um an open uh like

23:00

meteorological or weather forecast API to just get some hourly forecast information as well as some um like current conditions and stuff like that. uh we get that data out, we run it through like a simple transform where they like do coding of the weather conditions by number. So we turn that into like an LLM understandable text

23:19

format. Um make sure the API request is all valid and good otherwise the the workflow execution errors out and then we construct the actual forecast object in the format that we specified that the step should be outputting. So given this information, the next step we had was to plan some activities for this. Um again the format looks very simple. We have the ID and description

23:44

which show up here in the user interface. We have an output schema. So this step should return something of an object with a key activities. That's a string. This what we see here at the

23:55

bottom. And then we have a similar execute function which is basically that function that gets triggered whenever the step needs to be run. Now again we have this context object. However, we

24:06

access a little bit differently this time around. The context object has a function called get step result which can take either a string as a name of a step or the ID of a step rather or it can take a reference to a step. In this case what we're interested in is the actual forecast that we just received. So we can get that forecast information

24:24

by using the reference to the step that we just ran fetch weather. So the forecast then will look exactly like we specified as our output for the previous step. So what we do with this forecast is we create a prompt using the location that we wanted to plan activities for and then we just send like a JSON serialized

24:46

uh weather forecast. We also in addition to context in the execute function have a reference to the master class. So whenever you define workflows, if you register those workflows and whatever agents etc you might have into your master instance, they immediately become available here in all of the execute

25:08

hooks um in your workflow steps. So what we can do is to get a planning agent from our master instance and then I do an agent.stream with this prompt. I

25:20

stream it to standard output, but also I construct the actual step output into a variable and then return that at the end of the execution flow. Let's run this and see how it looks like. I'm going to open up terminal here because that's where we're going to be streaming the LM response. Let's try to do a weather forecast for

25:38

Austin, for example. So, I click submit here. First thing we see is the fetch weather step already executed and we're currently executing planning of the activities. That was actually pretty fast. So, we didn't see it streaming here. We'll just do that again for Cisco

25:51

for example. So now here we see that it's streaming uh the LM output as it's coming in. We see that both of the steps have completed and underneath here we see like the actual end result of the workflow execution. The most interesting part here being the context. Now this

26:09

you might remember is the object that gets passed around u to every step in the execution flow. that we have two steps here both the fetch weather and plan activities with their own statuses and outputs etc. In this case both the steps were uh successfully executed and in the fetch weather output you can see like the actual forecast object that we

26:29

created. So you see the state temperature information the condition location and this is like the chance of rain as a percentage and then plan activities being that final step with the actual plan um which looks like like this here. Um, so there's like a weather summary.

26:45

There's some specifically planned morning and afternoon activities, indoor alternatives in case it's raining, which it might today in San Francisco unfortunately. 22% chance. Um, let's also have a look at traces. Um, so we called this workflow twice on the first

27:03

execution. We called it for Austin. You see both the steps like uh a step transition to a step and then action as in like actual execution of the step. We see that both for the weather uh the

27:16

weather API calls and for the activity planning. Now on the fetch weather we mostly just see what is the context at that given time in the workflow execution. So at this point there's nothing except just the workflow trigger data or like the workflow input available. We also have a run ID which

27:34

is like a specific ID to that execution. So this other execution of the workflow will have a different run ID. Now um if we go into the plan activities action we will see that at this moment in time we do have a step that has already executed that's the fetch weather. So this is what our plan

27:54

activity step has access to when it's being executed. You also see a bunch of like um subspans here in our tracing because the plan activity step actually calls an LLM. So we also get the agents trace agent traces in this case um for um the planner agent and you see like the actual inputs that are given uh to this call here. You also see like the context that it has with tool calling and all

28:21

that kind of stuff and we we also have AI SDK traces um from the actual AI SDK calls that are doing the generation. In this case there's the uh AI stream text call. Um you see the input to that you see the output generated here stat weather summary um and activities etc. And you also see like token usage and and stuff like that. Now the other call looking very

28:46

similar except in this case um we've used a different city so the activities will will turn out different. So let's have a look at the actual agent here and how that all works. So as I mentioned, you always have access to the master instance in all of your workflow steps. In this case, we are simply getting something called a planning agent. A planning agent is basically

29:10

just um a toolless master agent with a very u specific set of instructions for how to format uh an activity plan. It follows it pretty well. So it lists out the dates and like a summary of whatever JSON information we give regarding the weather. Um the reason you see this

29:28

morning and afternoon activities is because we are very rigid in how we wanted to plan. So we wanted to specifically plan for those activity types and always give indoor activities if appropriate. Uh also not to give too much. So there's specific guidelines that we set here and etc. So pretty simple workflow. Um let's

29:48

take it up a notch. Let's use the same example but uh do something a little bit more involved here. go back to our workflows listing here.

30:00

So here's pretty much the same workflow except we've added um conditional branching in this case. So we start with a fetch weather step basically the exact same step as previously and then we have a conditional check where if the chance of rain is higher than 20% we plan indoor activities instead of planning like a general uh activity plan. If

30:23

however it's not going to rain then we plan activities as usual. Again the the inputs are the same. We have a trigger data specifying uh the city for the whole workflow as parameter. Um and in code it looks like

30:38

this. So again we start our workflow with a step fetch weather. That's always how the first step in the workflow is going to look like. However, the difference comes in here

30:49

where we do if and then we pass a callback function where again we have context available to us as well as the master instance if we so choose to. In this case, we don't need that. So, we're going to use the get step result function from context. We fetch um the results of the weather of the fetch weather step. Again, forecast object

31:09

schema looking exactly like we expected to. We check the precip um the raining chance of this of this forecast and then we do like a dot then plan indoor activities which means that if the condition is true then this will be the step that gets executed and if we wanted to add more steps into this if branch or the truthy branch we could add another

31:32

here. If however there is less chance of rain than 20% then we plan activities normal and again we could add another step in sequence to this branch here. Okay, so the plan indoor activities, let's have a quick look at that. It's very similar to the plan activities step. It's getting the same exact agent,

31:56

getting the same exact weather results from the previous step. However, it specifically prompts for indoor activities only uh for the date and location. Um so let's run this example as well.

32:14

So we saw that in San Francisco there was a decent chance of rain. Let's try that out again. We see there fetch weather call is being executed. Then there's like some conditionals being executed and it is planning indoor activities in

32:27

this specific case. So if we go into our context here we see again the fetch weather call results looks the same as in our previous example. We have some contextual information on which branches have been executed. In this case, the else branch was skipped because there's a decent chance of rain. We have

32:44

executed the if branch. And here's like the actual um the actual summary. And it's only given indoor plans in this case. Um since the weather is not the best unfortunately.

32:58

Um looking at traces for this execution. Again, looking pretty similar as in the first example. However, we see the same uh if actions here as well as the evaluation result that is actually going into the if branch and the else branch is skipped. And then in our indoor activities again

33:17

seeing like the AI SDK traces, we see some memory usage um as well from our threads and then here being like the actual stream text call from AISDK with our specific action plan. No, let's try with another city. One that where perhaps doesn't rain. Let's try Austin. I believe it didn't

33:36

say there was much of a chance of rain here. Yes. Uh no, in fact, there is chance of rain here as well. So, we're planning some indirect activities. So, let's choose city. I think Helsinki

33:47

weather should be pretty good today. A little bit cold, but not bad. I might need to change my threshold of 20%.

33:55

Let's just say 50% chance of rain. That's pretty low. Let's try that again. There we go. So, there is still a

34:07

slight chance of rainy. Not too bad, though. Um, it went we went into the else branch. So, if we look at our

34:12

result here, uh we see that the if step was skipped this time around and the else step was a success. So, we went into uh the planning activities branch. And here we see the same format that we're used to seeing from the previous example with like specific morning and afternoon activities and uh considerations there is some chance of rain and whatever. So again traces in this

34:38

case looking very similar except we see that the branch is what was executed and then again similar streaming context. All right. Uh let's take it one step further and make something a little bit more complicated once again. So here we have a similar if and else branching situation uh where we

35:06

first fetch the weather. If there's uh a decent chance of rain, let's say 30% at any given time during the day, then we run some a step called plan both workflow. If however it most likely is not going to rain then we plan activities as usual. Looking at the code here it looks quite similar to the previous example

35:30

except instead of planning indoor activities we run this plan both workflow thing and there's something called variables in here. Let's have a look at that a little bit later. Let's first dive into what the plan both workflow does. So instead of being a step is actually a workflow.

35:47

So you not only can pass uh or create a step and then put that in your workflow execution, you can also pass in a workflow that then gets executed as a nested workflow whose results you can then access in the context um of the other steps being executed. So this is a workflow that takes as a trigger schema or input a forecast in our familiar uh

36:09

forecast schema. And let's worry about this a little bit later. Um what it does is it plans activities with step plan activities and then instead of then plan indoor activities which we have seen previously. This is what we are used to

36:28

from previous two examples. Um it runs two steps. What this does is it actually kicks off both of these steps to run in uh in parallel. So it plans activities

36:38

and indoor activities at the same time. What we then do is we say dot after plan activities and plan indoor activities. So after both of these parallel steps have completed we run a synthesize step. So these two steps looks the same as before. So we don't really have to dive too deep into them. But let's have

36:58

a look at the synthesize step here. So the synthesize step is something that produces a familiar looking object with the activities key being um LLM output. Um it uses the get step result function from our context to get results of planning of the indoor activities as well as planning of like the general forecast based activities. It creates a new prompt just kind of

37:23

tying that all together. And since in this if execution branch um we know that there's a pretty decent chance of rain, it's going to ask an LLM to like combine these two activity plans together given that there's a chance of rain. It will then do the same agent stream call um stream things in STD output as well as build a variable that you can return as a step result. This act the synthesize agent um actually

37:50

looks like this. It's quite simple. We just tell it that we're going to give it uh two blocks of text, one for indoor and one for outdoor activities. And we wanted to make a full report um of the different possibilities. Um and the idea

38:03

is that it will give you activities to do in case it does rain, but also it gives you the options for uh if it doesn't like synthesize in a nice format. So let's have a look at what we get when we run this workflow. Now, we noticed that um in San Francisco there was a decent chance of rain. So, let's uh let's run

38:28

here. Although in this case, I believe the chance of rain was 30% instead of uh 20. So, we actually ended up in the else branch here to plan some activities. So, let's have a look at the results. Here

38:39

we have the fetch weather outputs here. Once again, we saw that it actually executed the else branch. And here's like the typical activity plan format that we've already seen a couple times before. Let's try changing this to instead of 30, let's say, uh 20%

39:02

chance of rain. By the way, all this code like hot reloads. So if I go and I change this the variable here, um you see that the dev server is immediately restarted. all the bundles are regenerated. So if I go here and run it again, it's going to use the new version

39:15

of the workflow as it's executing. So looking at the results here again, we see that this time around it ended up in the if branch indeed because there is a higher than 20% chance of rain. we see the results of the plan both workflow um in itself since it's a workflow it has a very similar structure as the

39:43

parent workflow which we executed has has a status for all the different steps that it has individually like plan activities has a status success and its output we also see the plan indoor activities and its output and then we see the status of the synthesiz step which yields a pull report that looks

40:02

perhaps easier to have a look which looks like this. It's not quite the same format since for our synthesize a agent was not asked to keep any specific formats or the existing format for the the two inputs that we give it. But this is this is what it does. It like does two specific suggestions for this is what your day should look like

40:22

if it does does rain or doesn't rain. Okay. So now let's talk about this variables thing. So how do we know to

40:35

map um how do we know to map the forecast here um from the parent workflow state? Well, what I use here is what we call variables. Um it's a way when you declare a step to say this step will have its inputs from its input forecast from the step of fetch weather and the path to the actual variable that we want to pass to it as inputs in this case mean pass the whole thing because what

41:07

we want as the inputs for this workflow is the entire forecast schema. Like if we look at the fetch weather step, its outputs are actually like this flat object with all of the fields in there. So in order to have the forecast object wrap all of those fields, we will use dot to like flatten the whole structure inside. We could also just do uh date for example, if we just wanted

41:32

to pass the date as the value forecast. Uh this of course won't work because the schemas don't match. But just to give you an idea, if there was a nested object in there, uh let's say if we had a temperature object that would have a min or max, we could do this to pass just the minimum value or this to pass the whole temperature object. This is

41:52

what it is for for the um needs of this particular this particular workflow step. You can also use this syntax with uh with just simply then or um or step as well. So you can use variables here. If we were to pass uh

42:11

let's say forecast and activities as inputs. Um you can do something like plan both workflow here and then pass the key activities from this. And now send send email would be a step that will take an input schema in the form of activities and forecasts and have its execute function be able to access those like so like

43:04

like so. In this case, input data input data becomes an object that has the key activities and key forecasts each with those schemas that we just specified um specified here. Anyways, that's variables. uh

43:19

quite handy for specifically if you want to run workflows as steps um because then whatever previous steps you have executed you can use as a mapping um to the inputs of that workflow. Now there's one more thing that we need to drill into here which is if we go back to our workflow here you might have seen this result object that I didn't really uh really didn't really

43:42

explain just yet. Um a workflow um essentially most often has some kind of like consolidated result and the way to specify what that would be is to specify a result schema and then a result mapping. So result schema in this case as a as a final result of running this plan both workflow. We want to create a similar result as for the

44:06

indoor and and regular activity planning which just activities of like object with activities key and a string value. And the mapping is exactly the same as variables in the sense that I say that in this schema the key activities comes from in the case of this workflow the synthesize step and its output schema

44:25

value activities. And if we wanted to use this in in another step we could do something like All right. So that's this example. So, let's change gears a little bit and

45:06

go into a go into a slightly different different workflow feature and go back to something a little simpler just to illustrate how that works. So, here we have a three-step workflow. First step, we generate some suggestions. Second step, we ask for

45:25

human input of some sort and third step uh is we run a travel planner. Now for this workflow you see that we also take one input which is a vacation description. So looking at the code um this will be our trigger schema is vacation description which is a string. That's the description of a vacation or

45:46

the kind of vacation that the user wants to take. The first thing we do again three steps run fully in sequence. First step that we do is generating suggestions which is an array of strings.

46:01

Um and in this case we get okay so we actually access slightly differently the the vacation description from the inputs of the the workflow. We you can also use the same getstep result function that we used um to get things from the activity planning steps by by passing the word trigger. This is the same as doing um that's doing context.t trigger data.

46:27

Essentially what we do is we again get a specific kind of agent from a master instance and then instead of streaming we run a generate call which is like a fully blocking call that then returns the full lm generated text for you and we return that as suggestions. However, in this case it's like a JSON parsed JSON parsed like

46:47

structured output. If we look at our travel agent, it basically just says generate three different options based on the type of vacation the user wants to have. Uh and yeah, generates like a description for all of them. So the next step after that was a

47:04

human input step. And this is where things get quite interesting. So we have here an input schema that we just very briefly went through. You can use input schemas to like map data with variables. um as something that you have

47:18

access to from the input data in the context. In this case, uh we're not using variables as you might see, but in fact, how this step is getting its input is through suspend and resume. So, which is a way that you can do uh like a human in the loop or an external system in the loop kind of interactions with your

47:39

workflows. We'll we'll see that in action soon. We'll first run it and then we can go back to the code and and kind of see how it all fits together. But essentially what this steps does step does is it sees if it has any input

47:50

data. If it doesn't, it suspends and waits for some input data to come in. If it has it, it just returns and keeps executing the workflow. Finally arriving at a travel planner step that creates like a final travel plan.

48:04

um using the selected destination from the human input step as well as using the original vacation description from the workflow inputs or the the trigger data and then calls u another agent which is like a travel agent that simply just makes a more detailed uh travel plan for the whole holiday uh explaining what kind of data it's getting

48:26

in. Um it puts those as two different messages. So there's like the user selection which is the city and then like an assistant message with um the actual location description here. So let's run this. Um let's say I want to

48:40

do a beach vacation of 8 days. So generating some suggestions. In this case we are no longer streaming anything since we're using the generate calls. We do see some debug logs here though. Um so now we see this uh little

48:55

form being rendered here um with a key and a value and you can click on resume. So let's have a look at the output and try to understand what's happening here. So looking at our step outputs we see first of all that the um suggestion generation was successful. There's a few different locations here. Um we have um

49:17

males like a short description of what that's like. Maui again um like a very short plan and we have Santorini in Greece and we have another step here human input but this is not a completed step actually um the only thing we see is that it has been suspended so the workflow finished executing but it's not done it not has not been fully executed just

49:40

yet so what we can do is in our form here we see from our code that this UN input step ex u expects that at some point it will have a selection given to it which is a string and if it has that it can continue executing and pass that forward the travel planner step. So let's add a selection here. P being selection. And

50:02

let's say we want to choose Maui for example out of those options. I click on resume here. And we see that it's now executing the travel planner step. Again, this using a generate call.

50:14

So we're not getting any data stream in the console for this example, but it should be done shortly. There we go. Now looking at our outputs again, we see again the same generate suggestions. Nothing changed here. However, we now see that the human input

50:33

step has completed and you see the selection here in the outputs. And finally, the travel planner step has now successfully executed as well outlining the full travel plan by the agent. Let's have a look at traces in this example to understand what's really going on. So we have again two separate execute calls.

50:53

One for when we initially executed the workflow and a second one for when we resumed the workflow. How those look different is in our first execution call. You see that we only have two steps. um the suggestion generation with

51:07

its own LLM calls as well as the human input step which has like this kind of default proxy storage like that's not the most important part but we we have like a persist workflow snapshot trace here. Um so what's happening under the hood here is whenever you call suspend in a workflow um which again happens in the

51:29

human input step here on our um on our arguments here we have the ability to always uh import a suspend function which will persist the current execution state which is always like a serializable state of all the previous outputs um as well as like the the currently active execution paths. And if you call then resume programmatically or through the user interface uh it will

51:54

then load that snapshot and then resume execution from that particular moment in time with all those active pads um that were active at the time of suspension. So looking at how the second execution went here is you actually see that it starts with the human inputs which is the step that was suspended and you

52:15

see that after that we pass on to the travel planner but it doesn't execute the first step at all in this case because it already knew it already knows that this part was done. We have its outputs in the snapshot. So when you resume the workflow, it loads all of that output state and it feeds it in to the human input step along with this new

52:33

this new input data from our resume call. So this is how you can do human in the loop interactions. Um you can also very well use this for interfacing with external systems. Um all of these things are also exposed via endpoints. Um in in

52:53

this case there is an execute endpoint which starts a new workflow. Um you can also do this with the client SDK. Uh for example, you can do this programmatically on the server side. There's also a resume call. So whenever the workflow finishes executing if in the outputs we

53:12

see that there is a step that has been uh suspended. Let's run this again actually to get another snapshot of what it looks like when things are suspended. So if in your active pass you have a step that is in a suspended state, you could then call the resume API not necessarily from human interaction but it could be from an external system like something triggers a workflow it's

53:34

watching the results. if it sees that something goes into a suspended state now at any point in time you are able to go and uh simply resume with additional context by an API call with like a web hook or something like that. So Tony I did want to just jump in and say it's about the 10-minute warning. So maybe if we spend another five minutes or so and then we can have a few minutes

53:59

still at the end for questions. So maybe we might might have to rush through the last two, but people can grab the the code from the GitHub and and take a look. We'll be okay. The last two examples are very short. So So we're

54:11

going to make it just fine. So on to the next example. Um the last example is a very simple illustration of how you can do looping whether infinite looping or looping based on certain conditions. In this case, let's actually have a look at

54:24

the code first. So we have a very simple workflow where we run an increment step. Um we have like an initial value to the workflow that we pass as an argument and then we increment that value. In this

54:37

case we increment it by one. Um and then until that value is larger than 10 or equal to 10 uh we keep incrementing it and then eventually once once this condition is no longer true we run a final step which essentially just returns the initial value from the um initial value from the context uh trigger data which is the workflow's input as well as the uh step results of

55:04

the increment step. the current value and like the initial value. Let's just run this to kind of get an idea of what the execution flow looks like here. Wrong one. This one here. Let's

55:17

start with the value uh three for example. So that was since there's nothing asynchronous happening here. It's quite quick. Quick look at the traces. We see that the increment step is being called like a whole bunch of

55:29

times. Um since we start at a pretty low value, it keeps incrementing it until eventually in our final step, we see that um the value is now 10 and the initial value was three. Uh if we're to call it with 15 for example, which is already larger than 10, then we see that increment step is only called once. And the reasoning for this is it's kind of like a dow while

56:02

structure. We always call increment once and then we loop until our condition is met. What this looks like in as a graph is quite similar to what we see in code.

56:13

So we first run always an increment step as kind of like a do while structure. We then have a loop check which sees if we still need to do something. Um if the value is greater greater or equal to 10. um if it's not then we run the increment

56:27

step again and we kind of loop this branch here and if it's done then we run the final step. Um anyways that's that's how you can do loops. Uh there's more docs on the on the website here on like the control flow section with some more advanced use cases as well. So have a look at those. Um and as the last

56:47

example I want to show something a little different. So we're not looking at a workflow anymore. We're rather looking at an agent here. uh

56:53

specifically an activity planner agent. If we ask what this agent can do, it'll tell us that it can plan weather specific activities for any city. So let's ask it uh for some activities today in Austin for example. You see that it uses a tool

57:12

called an activity planner tool. You also see that it streams some output into the terminal as well. And what it gives us is something that looks quite familiar from our previous examples with a weather summary and indoor alternatives. Uh in this case, since there's a high chance of rain, it doesn't really give us outdoor plants, but it also gives its own thoughts from

57:33

this. Like given the high chance of rain, it's probably a great idea to explore some museums and and stuff like that. We could also ask for sinki in this case is planning like our so this would be like the indoor activity plan from our previous example. Um and

58:00

this is like the general weather based planning example from our first examples where it gives like this very structured morning and afternoon activities plan and all that kind of stuff. Again it starts uh you can do a mix of outdoor and indoor activities. Um and yeah let's have a quick look at the code for this uh how

58:18

the agent actually does its thing here. So the activity planner agent quite simple. I explain that the the agent has at its disposal a tool um for getting the weather and activities based on that weather which is this activity planner tool here and then I ask ask it to give its own thoughts uh based on that report which is this thing that you see at the end here that it depends.

58:43

The activity planner tool itself uh is just like any other master tool would be has an input and output schema but then it's execute callback actually runs the workflow. So we get the step one workflow from our first example. We create a new run programmatically of that workflow. We

59:06

started supplying the trigger data in this case mapping directly to the the city argument of the tool. And after that run has finished we then take the results of the plan activity step and if successful can return its output otherwise we return activities found. As you might remember remember the plan activity step returns

59:27

an object of a similar form with uh an object with activities true in it. Now this is like the way that you can wrap workflows. You could have suspension and resume here. Uh in the docs you'll find

59:39

some examples of how to do this. um both using watch as well as using like an async await um based flow. So have a look at that if you're interested in using suspend resume inside of a tool for example. But uh yeah this is this is what the programmatic API looks like.

59:57

Again more information on the docs here. Um simply I think the overview part will already give you an idea of how that works. That's uh that's all the examples I have for you today. Let me know if you have any questions.

1:00:16

Yeah, that was that was a lot. So, we have a few minutes for questions uh before we jump in. So, think think about your questions uh just a couple kind of final notes. I'll try to take one minute

1:00:27

here. A bunch of links here to our GitHub to the website. Here's the Discord. It's on the b it's on the

1:00:33

footer of the website as well as on the top of the docs page. So if you if we don't get your question answered, we have a very active Discord where everyone on the team is there. So you can chat with us there. We have way more

1:00:45

events, more that will be getting scheduled soon and then uh you know connect with us. And if you uh haven't already, most of you probably already have, but if you haven't, please give us a star on GitHub. And if you want access to mastercloud, we are currently in beta. Please uh go you can click the it's in the header of the website as

1:01:02

well to get access to that. And with that, let's answer a few questions and we will uh hopefully get a get a few. Yes. Uh

1:01:14

Luciano, go ahead. Go ahead. Hey there. Uh thank you for the presentation. It was very very cool. Uh we have been

1:01:22

using Mastra at our company and one overall perception is that the how agents work in a way that you have a system instruction and you give it tools. You can pretty much in the system prompt also code a workflow and say you should receive this input and call this tool literally in natural language and the

1:01:49

thread becomes like the data structure that holds the state of the workflow because it can know like the tools that have executed the initial objective and what it is right now. What would be the I I just wanted to ask what is like the direction here. Do we expect to have workflows that are defined in natural language and the agent will execute itself in any way

1:02:15

that you form or do you still see the having a structured way to define workflows with step being a necessary use? U yeah that's it. I'll take this one. Go ahead Abby. Um, wait one second. Sorry. Just use my

1:02:35

mic. Okay. Sorry, I'm with Tony. So, what's up, dudes? Um, okay. Let me

1:02:41

answer this question. So, the first step in this journey for us was to make sure that we can make workflows that are pretty like sound in structure, right? Because the next step would then be to train an agent to create those workflows under the hood for you, right? So you

1:02:59

would be prompting in natural language under the hood these workflows get created and executed and because we've created this nice structure like we can like train you know essentially like focus it on the structure of our workflows and that's kind of where agent network is going. We're going to do a workshop about that and there's a bunch of like research we're doing so I don't

1:03:20

have anything to say today but the future is exactly what you're kind of thinking about. The problem is people do that today. It just doesn't work all the time. And that's like the thing. Sometimes it does work though and you're like amazed. But then the next time you

1:03:31

try it, it doesn't work and then you get customer issues and that's when people kind of drop down into workflows. Yeah. There's at least a couple aspects in which it really falls short is one is you definitely lack some like determinism. What's the word I'm looking for? Determinism. Determinism. um from the execution in the sense that the

1:03:49

larger the workflow gets uh the more probable it is that the agent just goes a little wild and starts doing something totally different than what it's supposed to. Uh also the more context that you need to define for steps you kind of get a similar problem. The other thing that it falls short on really is concurrent execution u because it can

1:04:06

only run things only sequentially more or less. Um so those are like at least two big things that workflows will unlock for you. Yeah, if you're trying to do concurrency with your agent calls, it gets tough because at least you have to manage this parameter called max steps, which is also kind of opaque as well as like what if let's say you did

1:04:26

max steps 100. What if it calls the like one tool 100 times, but it was supposed to call like a different myriad of tools, right? So, we're just not there yet, but we're going to be. That's like my belief. So, next question. Thank you.

1:04:42

Yeah, go ahead, Aaron. Hi. Um, thank you so much for this session. Um, we're

1:04:48

currently running agents in production and our system. It's a little bit um, it's like a multi-tenant system. So, we're regularly serializing and deserializing agents from the database.

1:04:59

Do you guys have any kind of support for that for agents or workflows to be able to serialize them or maybe dynamically create them or change them at runtime? Another good question. Obby, do you want to take this one, too? I'm back again. Um, yeah, dude. Uh, we're working on this feature called agent templates and

1:05:18

then soon work workflow templates, which would allow you to then crud these things and then update them and stuff. So, yes, not today, but yes, it's on the road map. Yeah. Do we have a do we have a timeline on that or is there a way to

1:05:32

track that on the road map? The timeline is soon. Yeah, within it's a it's definitely one of the top three uh thing features we hear most often uh from a lot of our customers. So, it is high on the road map. So, just one last thing, somebody

1:05:48

actually somebody actually added a comment about like serializing and deserializing XATE. Is that something that might be a way to kind of like jerryrig this? Yeah. Yeah. Uh we're adding we added an API and we're adding two more APIs to

1:06:03

fetch workflow runs which is the XATE serialized state. Um I mean you could Jerry Jerry whatever. Uh there's also some community contributors who I think built like a workflow creator personal project that can do this type of stuff as well. Um so

1:06:24

there are ways but uh I think you'd probably rather wait for the built-in way. Yeah, that said those are live. Um, so the the snapshots that I mentioned in the suspend and resume section for like human loop interactions and such. Um, we

1:06:39

persist the snapshot which is essentially the X state snapshot of the the execution of the state machine like every time there's a step change. So if you do access that API, it does give you exactly the serialized state of the workflow at a given time. So if you do have the tools at your disposal, but as as Abby said, I do recommend waiting for that feature because it's should be coming soon unless it's extremely

1:07:01

pressing. Yep. Okay, we are past time. There are some

1:07:06

questions here that we did not get to. Uh please drop into our Discord and we will try to get them all answered after this. So, you know, please, you know, if you want to copy and paste it now before I close the meeting, if you drop it in our Discord, we will do our best to answer it there. Uh, it's always good when you have too many questions, you can't get to them all, but

1:07:24

unfortunately, we do have to wrap this up. I do appreciate everyone for coming. Thanks Tony for walking us through all that. You know, thanks Obby for jumping in and answering some uh additional technical questions. And yeah, please uh

1:07:37

come to some more workshops, talk to us in Discord, and let us know how we can help you out. See y'all later. Thanks for coming everyone.

Watch Recording

YouTube