Okay.
And so what we have now is the worker node that is defined right here.
And it's quite long.
Um, and uh, it doesn't even fit on one screen.
I think I expanded the font size a bit so that, uh, but that does have that drawback.
Maybe I will make it a little bit smaller for a second, and we'll make it bigger again in a minute.
Uh, go down a little bit so you can at least see it all in one screen.
Uh, so this here is the is the, uh, is worker.
So it's got a pretty meaty system message, which I have built up based on my experiments.
And you will need to keep doing so too.
I added in here the current date and time.
I actually, for a bit made another tool to to come up with the current date and time, but I realized
that then I had to come in here and prompt it to be sure to use that tool.
And then I thought to myself, okay, this is silly.
I always want it to know the current date and time I put that in as a tool, and then I'm telling it
in the prompt to be sure to use that tool.
And that's just such a waste.
This is an example of something that doesn't need to be a tool.
It needs to be inserted in the prompt every time.
It is what we'll call a resource when we when we get to MCP time.
But it's like it's like a piece of information that we want to add in there.
So I just shove in the current date and time in the prompt.
I also, I had an interesting thing happen when I was using the Python tool that I saw that for some
reason, GPT four and mini misunderstood how the tool worked and thought that the code it would put
in there, whatever that evaluates to, would be what it would receive in the response from the tool,
where in fact, you had to put in a print statement in that code if you want to actually get back some
text.
And it didn't do that.
Uh, and so as a result, it was going backwards and forwards, trying to rerun again and again and
not getting any results and seeming confused.
Uh, and uh, so I added in this line, you have a tool to run Python code, but note that you need
to include a print statement if you want to receive output.
And then it started to work immediately.
So maybe that's just a GPT four a mini anomaly.
Maybe if I use the big GPT four, it would be fine.
It would have figured it out or it would just know.
But or maybe the way that the tool, the description in the tool isn't clear enough.
And I could always wrap it in a, in a, in another tool that would make that clearer.
Um, but uh, but regardless, this, this fixed it.
And this is such a good example of the experimental nature of this kind of work that you need to be
able to come in and just shove something like that in the prompt.
Maybe this won't be needed for what you do, but it was needed for me.
Um, and there was another example of, of where I came across something similar.
Um, and, uh, yeah, you'll probably find it yourself if you if you look through this, you'll see
other times when I had to tweak things, uh, to, to handle some cases.
Um, so anyway, other than that, this is all identical to what we have in Jupyter in the, uh, notebook.
Let me expand here.
Um, okay.
And now this is the router, the worker router, the decision, the condition on whether or not the
worker should go to tools or to evaluate it.
This is the utility method that converts our messages into a nice user assistant.
User assistant.
And finally not not not finally.
But the big the big guy is the other node the evaluator.
And this has again, a lot of pretty substantive prompting that I have tweaked over time.
That describes you're an evaluator, what you're there to do.
Uh, it's got the formatted conversation, the success criteria, the last response.
And then, uh, responding with your feedback.
Uh, and, um, I remember now, I added in this, I noticed that the evaluator was quite harsh and
never seemed to sort of trust that what the, um, assistant said it had done, what the worker said
it did.
The evaluator always said, you know, I don't know if this actually happened.
So I put I put in here the assistant has access to a tool to write files.
If the assistant says they've written a file, then you can assume that they've done so.
Overall, you should give the assistant the benefit of the doubt if they say they've done something,
but you should reject if you feel that more work is needed.
So you know, again.
And maybe this time I've gone too far and I'm going to make it accept too many times.
It's something that requires constant tweaking and refinement as you find cases that are that are that
work or don't work.
And of course, it's always good to add an example to give real concrete examples.
And there's some trade off, because the more information you put in here, uh, the, the harder it
is for Gpt4 to be coherent because it's just got a lot more information to absorb.
Uh, but, um, yeah, it's definitely it's definitely something that I found that giving these kinds
of hints and examples has helped me get better outcomes.
And you will need to experiment.
Okay.
So that is the evaluator we've then got at the end of it, I'll just mention again, remember at the
end of the evaluator, we, we we evoke the LLM with output.
And because it's, it's one that has a structured outputs which is what that with output means, uh,
it returns back an object, an eval result object populated, and then we pluck out the fields of that
object, and we populate them in our new state, and we return the new state as all nodes take an old
state, return a new state, and then this route based on evaluation, this is again another of these
condition branches.
We take, uh, we see whether either the success criteria is met or user input is needed.
In either of those situations we need to end, but otherwise we're going to bounce back to the worker
to give it another shot.
Okay.
And then here is the build graph.
And this after I made such a song and dance about this in the first couple of, of uh, of days of this
week.
Now this is like the easy part of the whole thing.
We create our graph builder for, for the state of the class that we have created.
And then we add our worker, we add our tools, we add our evaluator, the three nodes.
We add our our edges.
Uh, um, conditional edge.
This is not a conditional.
This is the if a tool is run, it needs to come back to the worker a conditional edge to choose between
the worker and ending and the start going into the worker.
And then we compile our graph.
Okay.
And then I've got this run super step function which is the one that actually invokes the graph.
So run super step then is pretty straightforward.
Uh, I've got uh, the uh, the random Uuid I've set as, as an instance variable sidekick ID.
So I set up the config this way.
And then the state the initial state that we will use to invoke our graph.
It is the message from the user for the success criteria.
It's either the success criteria that's passed in or if that's if that's not set, if it's null or an
empty string, then I use this default.
The answer should be clear and accurate.
Um, feedback on work is set to none.
And these two are both false initially.
And then we call our graph a invoke to kick it off.
And then we pluck back the user's thing, the user's message, the reply, and the feedback from it.
And we construct our history and that is what we reply.
And then I've also got this at the end like a clean up function.
And as I say, it's kind of as you'll see this gets called when resources get cleaned up.
And I'm not 100% sure if this is always cleaning everything up.
And so over time I will I will try and keep an eye on this.
And I may refine this as as we go, as I get, get to see whether this is properly cleaning things up.
So if it looks a bit different when you're looking at this code, then I might have found a better way
to do this that's more reliably cleaning resources.
Um, after after they've been used.
And I'm talking particularly about, of course, about the browser that we spawn this headless browser.
And the thing to be aware of is, okay, once we've done that, if we then kick off a new sidekick process,
it spawns another browser.
What have we done to that first browser?
Have we closed it?
Have we quit the browser that's running behind the scenes?
Uh, or running in front of the scenes as it would happen?
Uh, so, um, yeah, I've, uh, put this in to do that.
Okay.
And now on to the user interface, the app.