WEBVTT

00:00.120 --> 00:02.120
And a warm welcome back to cursor.

00:02.280 --> 00:07.840
And also we are coming now into week four Landgraf and into lab one.

00:08.120 --> 00:11.520
And it's not only welcome back to cursor, it's also welcome back to notebooks.

00:11.560 --> 00:14.680
You know I love these things I know the mixed mixed popularity.

00:14.960 --> 00:16.640
Uh with with with others.

00:16.640 --> 00:18.640
But but hopefully you'll put up with them for a bit.

00:18.680 --> 00:20.320
We'll use code as well this week too.

00:20.360 --> 00:21.040
Don't worry.

00:21.440 --> 00:25.680
So we're going to start by doing some imports as we get started.

00:25.680 --> 00:28.360
And then we also have some constants.

00:28.360 --> 00:29.360
Ignore these for now.

00:29.400 --> 00:30.600
We'll use them in a bit.

00:30.640 --> 00:31.320
They're silly.

00:31.680 --> 00:35.520
Uh and we're also going to have our favorite, uh, little thing here.

00:36.120 --> 00:39.360
And you may be wondering why we didn't have that during crew week.

00:39.480 --> 00:40.680
It was absent.

00:40.840 --> 00:43.560
And the reason is that crew just does that for you automatically.

00:43.600 --> 00:48.240
Crew uses the env file itself, and so you don't need to run it.

00:48.800 --> 00:49.280
Okay.

00:50.120 --> 00:54.280
Now I need to explain something called annotated.

00:54.520 --> 01:00.520
So hopefully you're somewhat familiar with things called type hints in Python, an optional feature

01:00.520 --> 01:03.080
that is often used in engineering.

01:03.480 --> 01:09.360
To give you an example, supposing that we have a Python function called shout that takes some text,

01:09.760 --> 01:16.720
and the job of shout is to print the text in uppercase.

01:17.000 --> 01:18.280
That seems fairly simple.

01:18.600 --> 01:22.800
And let's just shout hello like that.

01:23.600 --> 01:25.080
Hopefully no surprise.

01:25.080 --> 01:27.760
Hello in capitals comes up.

01:28.120 --> 01:35.240
Well, uh, the type hints is when you are clear to Python, uh, what is the type of variable that

01:35.240 --> 01:36.280
you're using at each point.

01:36.280 --> 01:39.920
So you can say that that text is a string by putting colon str.

01:40.200 --> 01:46.040
And you can put here that will return a string or it's not returning anything, it's returning none.

01:46.040 --> 01:49.240
But if we also have it, uh, if we leave it like this, oops.

01:49.400 --> 01:53.520
If we have it be returning a string, then it will be unhappy.

01:53.520 --> 01:57.120
But we would need to then also return text upper as well.

01:59.560 --> 02:00.440
And then it will run.

02:00.440 --> 02:02.000
So these are called type hints.

02:02.000 --> 02:05.810
And they are a useful way of specifying what's going on.

02:06.050 --> 02:13.050
There is a feature that you can use called annotated in which we could type annotated.

02:15.210 --> 02:16.570
String comma.

02:16.570 --> 02:19.010
And then we can put some message here.

02:19.330 --> 02:23.410
Uh, something to be shouted.

02:24.690 --> 02:28.370
Uh, and this is something I need to close the square brackets.

02:28.490 --> 02:30.410
This is just extra information.

02:30.410 --> 02:33.690
That's a sort of FYI that's included in here.

02:33.810 --> 02:36.130
Uh, Python doesn't make any use of this at all.

02:36.130 --> 02:42.170
But if we are going to provide this function to, to, to another platform or in some other context,

02:42.170 --> 02:46.090
someone might want to read how we've annotated it, and that might be useful for someone.

02:46.090 --> 02:51.090
So annotations can be used for this purpose of kind of tagging variables to have a purpose.

02:51.090 --> 02:52.810
So this should run without any change at all.

02:53.050 --> 02:54.690
That is completely ignored.

02:54.890 --> 03:00.370
Uh, and it's just just a useful way of adding some extra information in case, in case it matters to

03:00.410 --> 03:03.290
somebody else and it is going to matter to somebody else.

03:03.330 --> 03:07.250
Landgraf is going to want us to annotate, in order to tell it something.

03:07.250 --> 03:08.330
Let's come on to that.

03:08.330 --> 03:13.050
So I explain here again, you could have a variable like my favorite things that could be a list.

03:13.330 --> 03:17.170
And you could say that my favorite things, you could actually not just describe it as a list, but

03:17.170 --> 03:18.570
say that it is annotated.

03:18.570 --> 03:19.530
It's a list.

03:19.530 --> 03:25.770
And these are a few of mine I added as an annotation to my favorite things.

03:26.090 --> 03:28.490
Uh, so why do I tell you this?

03:28.530 --> 03:32.050
Well, it all comes back to these things called reducers.

03:32.370 --> 03:35.730
We are about to define our state object.

03:35.770 --> 03:38.050
And when we do so we're going to give it a few fields.

03:38.050 --> 03:40.570
And when we define those fields we have to give them a type.

03:40.890 --> 03:47.570
And when we give them a type, we don't just specify the type, but we use annotated to be able to specify

03:47.610 --> 03:48.690
a reducer.

03:48.930 --> 03:55.610
If Landgraf is expected to use a reducer, that is the technique use annotated to do that.

03:55.810 --> 03:57.970
Um, and that that is what we're going to do.

03:58.210 --> 04:03.010
And as it happens, Landgraf comes with with one out of the box that's very useful for us called Add

04:03.010 --> 04:03.770
Messages.

04:03.970 --> 04:06.450
Uh, and that is one that I just imported up here.

04:06.450 --> 04:10.170
So if you look up here, one of my imports was from Landgraaf.

04:10.810 --> 04:13.130
Message import add messages.

04:13.130 --> 04:15.010
So that is it's like a function.

04:15.010 --> 04:18.010
And it's a function that you can, you can annotate with.

04:18.050 --> 04:21.250
If you want to say, hey this is the reducer I'd like you to use.

04:21.730 --> 04:26.650
So to make this feel real let me just let's go ahead and define our state.

04:26.650 --> 04:32.290
So you remember step one in the in the puzzle is to define the state object.

04:32.290 --> 04:33.570
That is what we're doing here.

04:33.570 --> 04:35.250
We are going to have a state object.

04:35.450 --> 04:36.410
Now state objects.

04:36.410 --> 04:37.530
You can define them in many ways.

04:37.530 --> 04:39.890
They can in fact be any Python object that you want.

04:40.170 --> 04:46.290
It's most common to either have it be a Pydantic object that we met in the last week.

04:46.530 --> 04:47.410
Uh, it can be.

04:47.450 --> 04:48.730
Or we made it the last two weeks.

04:48.850 --> 04:52.850
Uh, it can be a pydantic object, meaning it's a subclass of base model.

04:52.850 --> 04:59.090
It can also be something called a typed dict, which is a particular type of, of dictionary in Python

04:59.090 --> 05:01.210
where you specify what the keys need to be.

05:01.530 --> 05:07.130
Uh, but but it can also be anything but it is quite common to use either pydantic objects or type dicts

05:07.130 --> 05:10.250
and we will use Pydantic, since that's something that we're familiar with.

05:10.290 --> 05:15.090
So we are going to have a state object defining the state of our system.

05:15.090 --> 05:19.010
And it only has one field and that's called messages.

05:19.010 --> 05:22.050
And that is going to store in it a list of messages.

05:22.050 --> 05:25.250
And these this list of messages is going to be passed around our graph.

05:25.250 --> 05:28.490
And over time it's going to build up as messages get added to it.

05:28.930 --> 05:32.210
And so we are going to say that it's it's something that's annotated.

05:32.210 --> 05:33.170
It is a list.

05:33.170 --> 05:36.930
So it consists of a list of things of messages.

05:37.530 --> 05:42.650
And we are going to then because we're annotating it, we can provide an annotation that's ignored by

05:42.650 --> 05:45.130
Python, but it can be used by Landgraf.

05:45.330 --> 05:52.130
And that annotation is where we get to specify the reducer, the function that will be called in order

05:52.130 --> 05:54.850
to combine one state with another.

05:55.050 --> 05:58.610
And we're going to use one out of the box called Add messages.

05:58.610 --> 06:02.650
It is a reducer that is used to add messages.

06:02.650 --> 06:03.770
And it's very simple.

06:03.770 --> 06:04.810
It's very vanilla.

06:04.970 --> 06:07.770
All it does is it assumes this is a list.

06:07.770 --> 06:11.060
And if you return something with with an and items in the list.

06:11.100 --> 06:16.420
It just combines it with everything else in the list before it concatenates these lists together.

06:16.540 --> 06:17.860
That's all it does.

06:18.220 --> 06:20.540
So hopefully that makes a bit of sense.

06:20.940 --> 06:25.860
Uh, if not, then you'll see it'll become clear as we use this exactly what's going on.

06:25.900 --> 06:30.500
And and why were the use of this and the reducer and how it's working.

06:30.780 --> 06:32.780
So step one we define the state object.

06:32.820 --> 06:35.900
Step two we start the graph builder.

06:35.900 --> 06:39.660
And that is just a matter of calling this thing called state graph.

06:39.660 --> 06:43.100
Instantiating a state graph passing in state.

06:43.220 --> 06:47.100
And one thing to to get your head around here is that what I'm passing in there.

06:47.100 --> 06:48.260
The thing I've just highlighted.

06:48.260 --> 06:50.460
It's not an object I'm not instantiating.

06:50.460 --> 06:55.580
I'm not I'm not creating a state and passing that in with with messages and so on.

06:55.620 --> 06:57.500
Now I'm passing in the class.

06:57.620 --> 07:01.340
I'm passing in the type of thing that represents our state.

07:01.340 --> 07:04.900
That is what I'm using to create my state graph.

07:04.900 --> 07:07.940
And this is beginning the graph building process.

07:08.060 --> 07:12.580
This is part of the five steps before we actually run our Agentic framework.
