Getting the transcript
Reading the captions from YouTube. A video nobody has opened here before takes 10 to 30 seconds; this page fills in on its own.
Getting the transcript
Reading the captions from YouTube. A video nobody has opened here before takes 10 to 30 seconds; this page fills in on its own.

AI Engineer · @aiDotEngineer
This video has no Most replayed graph yet: YouTube shows one only once a video has enough views. These are the moments viewers replayed most in AI Engineer's most watched videos.
Most replayed moment at 18:45
4.8x that video's typical replay level
that they're they're changing they're changing things in the database not yet. You want to run them through the ontology first and make sure that works. Okay. I only got an I've got I've got another I've just a short time. I'm going to try to show you some of the things that um that you can
Said at 18:37
Most replayed moment at 16:13
3.6x that video's typical replay level
method signatures, the program layout and the call stacks. So here's some examples. I don't think you'll be able to read this one, but this is like the level of abstraction we're at. It's how we're actually going to lay this stuff out and how these systems are going to interact. Dylan Mulroy from Cloudflare talks a
Said at 16:06
Most replayed moment at 6:57
5.9x that video's typical replay level
do light mode. It's I It's not my nature, but sometimes. That's better, yeah? Okay. So we have we have a model and we're trying an old LG Sorry. We We shouldn't have seen that. No, we'll
Said at 6:50
The graph counts replays. It does not show where viewers stopped watching.
Words
11,652
Runtime
1:04:26
Speaking pace
181wpm
Reading time
49min
181 words per minute, the same as the 181 median of 349 measured videos. That distribution comes from the 349-video hook study.
Opening (first 30 seconds)
Welcome to to the workshop. I am Jonas and this is Misha. We both work at Iterate. >> Hi. >> And the this is going to be a chaos. I think pure chaos. First of all because we only we only decided last Monday to do this. And then I was like a bunch of personal stuff and half term and the kids were sick and then this morning we came here and I thought this was going to be like a like an hour and 20 hackathon or something like
91 words, the words spoken in the first 30 seconds at 181 words per minute.
Free, no signup. See how the first 30 seconds hold attention, with rewrites.
Sentence shape
| Measure | This transcript |
|---|---|
| Sentences | 691 |
| Average words per sentence | 16.9 |
| Longest sentence | 185 words |
| Questions asked | 76 |
| Sentences containing a number | 21 |
Most used terms
Filler phrases
976 in total: like 273 · um 247 · uh 235 · basically 47 · you know 37 · actually 34 · sort of 34 · right? 32 · kind of 18 · literally 10 · I mean 9.
A literal whole-word count of the same phrase list the Prepublish browser extension uses, so a phrase inside another word is not counted and a phrase used in its ordinary sense still is. It is a count and not a judgement.
What this transcript is
Every word below is the caption track YouTube publishes for this video, pulled from the video itself and reproduced unchanged. It is not Prepublish's writing, not a summary, and not a re-transcription: it is the video's own published captions. English captions, generated automatically by YouTube, in the video’s original language. Source: the video on YouTube. A channel that would rather this page did not exist can ask for its removal through the contact page, and it is removed.
Welcome to to the workshop. I am Jonas and this is Misha. We both work at Iterate. >> Hi. >> And the this is going to be a chaos. I think pure chaos. First of all because we only we only decided last Monday to do this. And then I was like a bunch of personal stuff and half term and the kids were sick and then this morning we came here and I thought this was going to be like a like an hour and 20 hackathon or something like that.
And then we came here and we're told you're going to do it without an audience because of some fire thing. And now there's an audience again which is amazing. So we're going to do we're going to try and do this as like a improvised hackathon but I'm only just pushed the SDK literally 1 minute ago and Misha is going to try and and sort of like live fix it. But I I hope it'll still be worth your time because I think there's sort of some hopefully at least some interesting ideas or or maybe like one way to put it is I would like to find out whether this is like dumb or cool.
And and the and you can help me with that. So please also just like ask clarifying questions because part of this the reason we said last week, okay, let's do this workshop is because these have been ideas that have been kind of noodling around over the last year but we haven't really actually done anything with. It's not really like a commercial value to it necessarily but I think it's basically how I would like to build agent harnesses.
So you know, noodling with this for a while now and you know, obviously you've got like Claude and you've got pie now but back in the day you didn't and so you make your own coding harness and there's all these different ways to do it and I think the way I would like to do it is I would like to do it purely event sourced. And I say here aka debuggable and that is because everything kind of skirts around of being event sourced like all these things without quite being event sourced.
There's always something that has a side effect that you later can tell, and then you can only see it in the hotel traces or something, which doesn't really make sense to me because normally these these these agents, the way they work, and we'll see that in a second, is they already have a log of events, right? So, you So, if you just say everything that could possibly happen is in there, it would be really easy to debug.
Um and as we'll see, hopefully, a little bit strange, but potentially in other ways also really easy to to extend. Um and then the second thing is I want I want this to be extensible. And And we've seen this, I think, with Pi, which is was just incredible. Um how valuable it is to make an agent extensible, not just by humans, but also extensible by itself. Um and um one thing that I want in the extensibility is is I want I want it to be composable.
Like, I don't think we'll get there within 1 hour with all of you, but but maybe afterwards, if you say, "Oh, this is actually cool and not dumb," we'll keep working on this, and you can say, "Oh, I made this extension. You made that extension." And you can combine them. And um um because I think we don't really yet know what is the best recipe for for for agents, basically, for agent harnesses. And it's been too hard to experiment, even in Pi.
Like, everything has to run in a single thread in in in in like one process over here on this particular computer, and so on and so forth. So, I think I think we we can maybe do a little bit better than that. Uh then, I think it should be on the edge, publicly routable. Um Like, the way I think of it is basically an intelligent entity, like a digital one, that's not a robot in the future. It's just internet-connected uh basically server program, right?
Like, it just speaks HTTP. So, the slides broadly speaking, that should be sufficient for almost anything. And then I would just put these agents on the edge, speaking to the internet straight away. Uh this is not very safe. None of what we're doing today is safe, by the way. There's no authentication, you'll see. You'll all be able to see everybody else's event streams and agents and and whatever else. You should not put any secrets in the actual payloads of the events, or rotate them afterwards, right?
So, we can um you know, those things can be solved. But, broadly speaking, the moment an agent exists, it should have a URL. That's just like That's just my opinion. Because otherwise, like you end up making all these things and then you tie yourself backwards inventing a connector concept just so you can get Slack messages in or or God knows what. And that I think that should be really easy. Um. Or like maybe like a human should fill in a web form and the result of the web form should be input for the agent again or or something like that.
That's kind of like the same thing as as a Slack webhook. And then it should be distributed. And this is potentially like a very double-edged sword as we'll see, like right? But but by distributed, I mean you should be able to have an agent running sort of on one computer here on a server and my my plugin running over here and your plugin running over there and yours is written in Rust and mine is written in in in TypeScript and it all just doesn't really matter.
Um, and the reason that is bad is because you will eventually get race conditions and loops, right? Like sort of like two plugins kind of sending messages back and forth creating like an endless stream of events in your agent. Um, but on the flip side, you have those issues normally anyway in in in most agent harnesses I've seen. So, it's it's quite good if you if you kind of pre-empt that a little bit. Okay. So, let's um, let's talk about this thing that we have invented for um, oh my gosh.
Um, what is this? This isn't the same as in my file system. So, I'll use the one in my file system. Um. Basically, we have created this this service over last week called events.iterate.com. It has a web UI. Um. And we can we you can use that. I I think you'll certainly use it. But, for now, we'll just play with it with curl because I think it's it makes it in some sense more more tractable. Um, in the in the agents um, in the events app, we have this concept of agent paths.
So, just like a A in a file system, every agent has a path, has a hierarchy, and you just have uh here, you can show this here. You just have raw events. This is YAML-formatted raw events in each of these paths. And uh that is basically the the the entire uh the entire primitive that we're going to be building our agent on. And so, we can start by playing with this. We can say, "Okay, we we have a path prefix." If you copy this and from the repo that Misha's going to put it in the read me in a second. >> I'll I'll add workshop.md as well. >> Yeah, uh yeah, okay.
May Oh, yeah, maybe that's why. Um >> I I added the read me, but not the workshop. >> Yeah, so uh basically, um let's set ourselves a path prefix here. In my case, that is just going to be uh Jonas Tempelstein or something. Um they start with forward slash, by the way, which is a little bit um awkward potentially, uh but the but the service is very tolerant of you URL encoding your slashes or doing whatever you want, but I want I I wanted good curl economics, uh but I also wanted them to start with a forward slash.
So, you have like a well-defined root. Then for the base here >> It is now pushed to the repo, but have you have you shared the repo? >> Oh, yeah, because now you could actually do this on your computer. Uh let's do that, actually. If you go to um github.com/iterate, there is an an AI-engineer-workshop. Um Uh and in there, you should be able to If you click on this workshop.md file, that's what we're going to now going through.
So, you should be able to copy and paste the curls from there. And again, there's no authentication, so you can just do this. And uh in in fact, why why don't a couple of us >> our live deploy events. iterate.com. >> Uh like like like this is entirely just sort of like a proof of concept of um uh how I think this should work. Um Well, basically, what we're going to do is we're going to turn this simple event stream into a fully fledged agent without like really deploying any server software uh or or anything like that.
Um Maybe uh yeah, I should be able to see if if anybody has managed to do it. I'll wait until two or three people have managed to successfully curl something um and then I'll carry on because I think it'll be it'll be good if you if you if you curl uh at yourself. So, it's here in this AI engineer workshop workshop.md. >> If two people have the same name, that's going to cause problems, so >> It doesn't matter. Um it's that's fine.
Uh Okay, there we go. Got a few people. Um okay, so this pretty good. Um By the way, uh that you might see this here and there. There's also this thing down here called project slug. If you really start stepping on each other's toes, you can just type what like use a different project slug and it's like a completely new database, a new name space. Um you can pass that in as an HTTP header if anybody needs that later.
You can you can ask me. Uh Okay, so now we have a few people curling things. I will also for start curling things. So, uh now I'm just going to say hello world uh here to my stream. And it'll come back and and and we straight away we notice like a few things. There's a basic event envelope shape. We have a type that I've just invented here. Events don't need to have anything but a type, but most of them also have a payload.
Uh then um the uh there is the stream path which came from the URL that we posted this to and there's an offset. This is just an auto-incrementing integer that starts at one. Uh and so there's basically like a point of serialization at the server that just increments them and you get a created created at. Uh and then in here what we can do with curl, which is quite nice, uh if you do {dash} n, you can do uh streaming uh streaming SSE.
So, this here is literally nothing magical. This is literally just you know, {slash} Jonas Tempelstein uh {slash} hello world. This is literally the curl that we're doing right here. Um And um boop. There I can see the messages coming through. Very nice. And I can um I can add another message and now um basically uh all the all the messages will show up there and there's also a um Uh oh, if you do {question mark} live equals true, this is inspired by the durable stream standard, but like ever so slightly different.
But if you do live equals true, the connection will stay open and it'll just keep sending you more events as you as you put them through. So, this is sort of already you know, um like you could say this is an AI agent if Misha was simultaneously giving responses to my hello world. This would already be an agent. And then there's a my my eyes told me you can um if you're going to be doing that a lot uh you can pipe this through said, get just the data elements, and then pipe it through jq.dot and then you get a little bit nicer formatting.
So, this is sort of like this is so trivial that I actually do spend a lot of time in curl just curling it. Uh then, what can you do? Um the thing is very tolerant just in general of of stuff you post to it and this will become relevant if you wanted to say send webhooks from random third parties there. Like my theory is always that like the LLMs are good enough they can basically just consume raw webhooks from anywhere and and they'll roughly do the right thing.
So, what the what specifically the server will do is if you send it something that doesn't validate like hogwash here it says there's there's no type property so there's not actually a valid event. Then you can see here what it has appended is basically an error. But it because we're event sourcing the error is also just an event and it just says here, "Okay, um you have a an invalid event appended um event." Oh, another thing um that we we will notice is that the type here uh that our server has created it starts with https events.iterate.com.
You don't have to do that uh but that is something that we like to do because that literally leads to the documentation for that event type. And if it's going to be an opaque string, like why not make it make it something like that. But uh obviously you can you can just do, you know, single words or two words or whatever. Um but you will see these URLs and they're just they're just types. Um then uh what else is interesting that we can do?
I mean, this is kind of boring, but you know, it again, if you're going to do webhooks, you have to kind of put an item potency key in, which just means if you have the same item potency key twice, you don't get um you don't get the event appended twice. You can pause a stream. I think in the interest of time we can skip that. You can resume a stream. The reason that pausing is important and is we put this in even though we literally just made this a couple days ago is because of the infinite loops.
Like it's very very easy to accidentally put like, you know, thousands and thousands of events in a in an infinite loop in the thing. And so if you put more than 100 events in a second or something, it is just going to circuit break and then the stream will be paused until somebody unpauses it. So basically, if you try to um you know, actually let's do that. Because again, like for those of you who haven't seen event sourcing, this might be a bit weird.
Like how do you pause a stream? Well, you pause a stream by uh what oops, this is the wrong one. You pause a stream by appending an event that uh says you're you're paused. The only external interface to the agent is oh, um now it's complaining. Uh why is it complaining? Ah, because I think there needs to be a reason or something, maybe. Uh yeah. Reason demo. Yeah, there you go. So now this thing is paused. So now if I um you know, try to send it the hello world event from earlier, it's just going to barf and it's say, "No no more events allowed." And that is one like that isn't one thing that doesn't appear as an error in the stream because otherwise you would still get infinite numbers of error events.
Um Uh then, I mean, there's other weird and wonderful things you can do. I I don't even know if we really have to do this, but uh, there's like um, I have made a plug-in for this already uh, that makes it so that if I put this JSON object transformer configured event in, what it'll do is it'll just observe certain events, rewrite them a little bit, and make a new event out of it. But, I think that's a bit advanced, so we'll we'll do it later.
Um, um, it can also do weird things like it can uh, you you can schedule you can schedule things. Like some agent SDKs you'll you'll know can do this, but uh, here, you know, if you want like an like a heartbeat event every 5 seconds, uh, oh, oh god. Now, I need to resume the stream because it's paused. Uh, let's see. Stream resumed. Okay. So, now I am just creating uh, this heartbeat event every 5 seconds, which can be quite handy, or you can schedule something for 10 minutes in the future or at a certain time.
And again, it's just an event that says, "Do this thing in the future." Um, mm mm mm. Um, I think I will skip over these, but um, you can cancel the schedule. You can tell the stream by appending an event to send your server or some third-party server or your you know, your Slack API endpoint or whatever an event every time an event gets added. Uh, so you can basically uh, subscribe to the stream. Uh, here we're subscribing in our in our terminal.
We're doing a pull subscription, right? We're doing we're we're connecting to uh, an HTTP server and we're getting uh, we're pulling uh, pulling um, with the HTTP client and they're the HTTP server and we're getting an SSE uh, response stream of of streaming events, but uh, it can also do the other way around where it will push you the stuff that gets appended or push you a filtered stream. Um, uh, which can be quite handy.
Okay. So, um, let's maybe stop there because I know also um, it wasn't really clear from the session description how deeply technical this was. And so, let's take any questions on what is even this thing that we're going to be using for for the next 45. >> But, questions have to be submitted as an event to the question stream. >> Yeah, exactly. >> If you have any trouble using the question >> Um Does I assume lots of things don't make sense, so please do ask them because I think this will be extremely like random and strange so far. >> What does Iterate do in your company? >> Oh, we we're like a we're like a hacker hobby club at this point, to be quite honest.
Like we we we are we have not got a launched product. Um but if we did, it would be I think based on this architecture. It's like anyway, I'll tell I can talk about it afterwards. >> Okay, okay, okay. >> But, it's yeah. It's more it's more home brew hacker club than than like commercial enterprise at the minute. But, it'll get there. Yeah. >> I have a question. So, I know that we'll be building event-based agents. >> Yeah. >> And you like maybe that's a basic question, but like agents that are on the market right now, aren't they event-based?
What's the like >> It's just um I think it's just the API like if you have you tried to make you know like a like an open code extension or plugin or pie extension or cloud cloud extension, and they all have like an API surface that is a little bit bigger than what you would have or what we're going to have in in a minute. It's not like by much, right? But, like okay, like maybe the streaming chunks for partial completions are a different kind of thing for some reason rather than just an event of type I've received, you know, like five letters of a streaming response.
To me, that's a perfectly valid event and and and the benefit then is that you can that can you I'm kind of like a one abstraction kind of guy, right? Like this this should be like a like web standards-based, it should be there should only be one thing, which is an event, and then as you'll see like the the thing that that was at the top of this file. I think you can build a super expressive state-of-the-art coding agent by just implementing like a stream processor that reduces over the event stream and occasionally enacts side effects.
That's That's all it does, right? Like it just sits there and says, "Okay." I'll show you that in a second. Like it's it's a bit weird, I would say, weird way of programming. Um >> So, if I understand correctly, you're sort of saying you take events that you get generated from an AI model and then you're basically going to apply them through this stream processor. Uh is that the idea? >> The stream processor is or like the the events that iterate.app is the storage.
Like you can almost think of it as a database. Like one one You know Do you know Convex is like a sort of you know, they they kind of give you the illusion that they're running TypeScript in the database. You could almost think of this This could be like a programmable stream or something, right? Because actually one thing that you can also do, we'll we'll see later, once you hack on your stream processors, you can also make an event that contains the source code of your stream processor.
And then it'll just run on every event. And so like it's basically it is like it is like the I think you can experiment with a huge array of different kinds of agent harness implementations that can respond to real events on the internet and make real API requests without deploying your service or something like that. All you need is this sort of streaming streaming service that um has some of some of these things like specifically needs to be able to wake up, you know, like other other APIs and and programs and so on.
I don't know that. Yeah. Um that Does that answer your question at all or >> Yeah, I think so. >> Okay. So, we try and make uh now a um like a like a slightly more serious version of these curls. Um so Does anybody here not know TypeScript? I think So, I think the like one of the arguments in favor of this architecture that I also put in that um in that uh in the in the blurb, I think, is this is in principle polyglot, right?
And there is a uh like in in any language there is at events.iterate.com/ uh api/docs you have just I mean, this is an exceedingly simple API, right? Um uh you can you can make yourself There's an open API spec. You can make yourself a client and so on. But for the purpose of this uh this um uh workshop here, we'll just do a TypeScript version and we've shipped a client in a in a uh NPM package already. But I I I I just wanted to point out like even though we're doing everything in TypeScript, the whole point is that we wouldn't have to, right?
But we just have to do one thing uh for this workshop. Um Okay. So, let's uh let's do do something pretty simple. Um Uh is the uh AI engineer workshop um package uh now up-to-date and working? I think it is, right? >> so, yeah. Uh you might need to pull your repo cuz there was a client-side type error. >> In the iterate repo? >> Uh no, the in the AI engineer workshop. >> Okay, that's fine. >> I think the example is TS. >> Yeah, but uh I'm I maybe I will actually use that.
Then then I'll be able to experience uh the same the same bugs if there are any. Yeah, that's probably better. Okay. Um Okay. So, uh I think um if you wanted to just have a quick start, you can uh you can just pull uh clone the AI engineer workshop repo. Um there's already a teeny tiny example file in there. And then we'll just add a couple more um as we go along. >> And the workshop.md has runnable curl as well. >> Nice, yeah. >> That does well.
If you wanted, you could put a couple like a couple of the follow-on examples that are in the iterate repo that have actual processors. Um Yeah. >> I can take a look. >> I don't know what's going on here. Ah. There we go. Hm. My computer seems to have uh slowed to a crawl trying to open a cursor window. This has been unfortunately like uh uh somewhat regular occurrence recently. Uh Okay. Oh, oh no. I think this might be what you mentioned about the internet.
I think it's just struggling because it can't open a terminal because the my my terminal tries to connect with the internet. Hm. Oh, well. Then let's do that. Um No, it's not the internet. Or is it? There we go. Okay. Okay. So, we have here um we have packaged up an SDK here to this uh AI engineer workshop um package that you should be able to just PM PM install or you just use uh use this example here. And then basically uh what what did we need in our curl, right?
Like we needed a base URL which is just events.iterate.com. That's where our server is. Uh we can use a path prefix um and um then we can uh run this function here called create events client that is from our SDK and then this is under the hood this is I really don't know what's going on with this terminal. It's very strange. Hm. Okay, maybe um everything is just incredibly slow. >> You want to try mine on this? >> Um >> Okay. >> Maybe, but there's nothing actually hogging the CPU.
It's just I I think I do think it might be actually the network, but we'll see. Um So here. So here you have um I don't think this is picked up the Anyway. Okay, so this is basically what we were doing just now, right? Like we we say, "Okay, we're making ourselves a client uh and then um here there is a function called stream. This is basically the um the the the right hand side of the of the terminal that we had earlier and then you say live true and giving the stream path.
And we can say, "Okay, if if uh if the event is not of type ping, we will do nothing, but if the event is of type ping, then we will I mean, this is a completely unnecessary helper down there. Uh then we can just do client.append. I don't understand why the um the the TypeScript language server isn't picking up any of the types for me, but I can't tell if that's just um or it's just being weird again. >> Your an example let me see.
Anyway. Um. Could quickly switch IDs. >> No, it's fine. It is working for me. >> Okay, yeah. I think this is unfortunately like a sort of cursor. Okay, and then you should be able to just if you have a modern version of node, you should be able to just run um uh or maybe not. Did I make it um uh It says invalid type script syntax. You know what, I'm just going to I'm just going to restart cursor. I think that is worth it.
Is anyone able to run this example TS on their computer? There you go. >> I am. >> Hm. Okay. Um, and are you able to send a ping to it and get a pong out of it? Okay, very cool. Okay. Hm. Um. Yeah. I don't Yeah. I wonder if we use use I don't know if you can see this, but basically all my commands they have like a several second delay. Which is >> Yeah, it's looking to me if you want to just swap laptops. >> Um Maybe.
Yeah, I know, I know, but it it's just Yeah. It's just my editor doesn't work. And I also have several non-responsive uh cursor. Sort of I feel like this is uh unfortunately a pattern with cursor recently. >> Mhm. >> I >> If you want to swap laptops, it does seem to be working okay for on mine. >> I would just give everybody 60 more seconds to just get get the basic demo working and then >> Just let me know. >> Yeah, because I think using some Yeah, there's still almost an hour to go.
It's not good to use somebody else's computer. Maybe I will continue on yours and I'll just restart my computer. I think that's a good idea because we can Yeah. Dum dum dum. >> I also have example 01 and 02. >> Oh, really? Brilliant. >> I think working with something >> What's your keyboard layout? >> Uh probably same as yours. >> One can One can One can hope. Uh okay. Entire screen. >> the same. >> Uh Uh it pretty good so far.
Um What have you got a terminal? Uh so node examples 01 hello world Okay, perfect. Yeah. Well, this what works flawlessly. Uh so, um Has everybody got that more or less working because then we can just make an open AI coding agent now. Um I think that's all we need. Let's maybe I'll ask um Do you have a speech control in here? >> Uh yeah, it's control and option. It's kids one. >> Yeah. And then? >> That's it. It's recording. >> Hello.
Oh. Cool. >> See that red bar is >> Um Hey, I would like to make a third example uh called agent processor and for that we need to install uh just the normal open AI SDK. Please uh do that and just make me a new file that looks like the hello world processor. Okay. Um Okay, so um I've just got to gather everybody again after I left you for about uh 10 minutes. >> Yeah. >> Here, this is a normal uh pretty normal spaghetti code TypeScript program, right?
Like uh basically what we've done here is we we sort of like uh doing some boilerplate work. Um uh here if we want to subscribe, we we have to make a subscription. Um Oh my gosh. This example that you put in there has like an abort signal and and handles all kinds of things and and um anyway, the the um I think um uh the way I think about what we're really doing is we're we're writing a stream processor. And if you've never done stream processing, this this might be like a bit weird and people use slightly different names for for these things, but really what we're saying is there exists some kind of world state that we're interested in that can be derived from the events.
In this in this example here that Misha made, we are trying to count the number of times an hello world event has been encountered in the stream. And then you can write the entire logic of your program as effectively a reduce function. This is this is synchronous and it just it just looks at all the new events as they come in and then it updates the state. That's all it does. So it takes state and event and it returns the new state.
Or you can just also return nothing, it'll it'll be fine. It'll just ignore it. And um and then you can you should not do side effects in this reduce function. And the reason I've split the reduce function from from after append where you should do your side effects is because if you think about what happens if if your program goes to sleep, right? Like you're you're closing your laptop. At the moment everything's running on our laptops, you know, 100 new events go into the stream.
Some of these events might in the future need to trigger LLM requests or something like this. And then you bring you open your computer again, you start your your program again and you don't want your program to go and make a ton of LLM requests for all of those 100 events in the past necessarily. Instead, you want it to sort of like catch up all the way and then decide what to do with the state at the end. And so we've made this like super lightweight abstraction here of a processor that basically gets hooked up into a processor runtime and then what it does is it it it splits your work into reducing events into state and then if you want to do some side effects like for example appending appending to uh uh you know, to the same stream again, you can do this.
By the way, I think I think you can also do this which which is like potentially uh it's pretty interesting. Um Like uh you know, you you can literally just append to uh you know, like a child path, or you can append to a parent path, or or or whatever um else you want. It's basically like a a meant to be like a file system. And so, if you wanted to build sub agents on this thing, all you would do is probably you would just append to dot {slash} you know, Boris, and pretend that Boris is a sub agent.
And then you would just subscribe to some special events that Boris might output, like I have the result. And then you would automatically be woken up again on the parent when Boris has the result. Um Is this confirmed, Misha, that this runs? Like, how do you run this? This just exports the um Like, you need you need the runtime, right? >> Yes, there is a CLI command that I now can't remember because my agent has been running it.
Uh where you can You should be able to do PNP and W in the off of the file, I think. >> Did Did you do all that just now? >> I did that about a week ago, but you may have changed it. >> no, yeah, okay. So, okay. Okay. Um let's go to our repo. Like I promised, this is uh a little bit The These are the um So, you can actually also do this. If you go to iterate {slash} iterate AI engineer workshop um here there are a bunch of examples uh of files that are um >> Uh workshop two.
I was going for workshop two. >> Yeah, I also >> It's out of date one. >> meant to be uh meant to be renamed. Um Ah, here. This is This is This is basically the snippet we want. >> Okay. >> There is this um there's this thing uh that you can have um So, here now we've just made a processor, right? Like, this is just like a sort of inert thing. And then um there's a thing called a uh pull subscriptions processor runtime.
Um, and all that does is it takes your um it takes your uh your processor that you just made and it uh runs it. Um >> I think you probably need to assign it to a variable cuz you're just export default above. >> Um, yes. do do do do hm hm hm Okay. Um Uh and here let's just say uh just see if we can run this. do do >> So, a question. Should we should we like this >> Uh yes, but unfortunately they need to be modified uh um in order to uh um do anything interesting. >> Because I don't see them on GitHub. >> Um >> Yes, those ones are those ones are were added in the last few minutes, but uh you >> Yeah.
I give slightly bad copying instructions. Um but I think I think >> It's uncommitted here. >> Yeah. hm Uh I think the bu we're just going to have to sort of like slowly slowly build it up in in this repo and then uh push it once it works here unfortunately. Um so here uh basically what I've now done is I've taken this processor and I've hooked it up uh into this runtime and all the runtime does is it's just this like boiler plate for for consuming the stream and running the reducer and running running um uh the uh after append hook and what we should see is once you submit hello world into this into this path here that is just Jonas {slash} example.
Uh, you should get a response there. So, if I go here in the in the UI and I go to Jonas {slash} example and I think I said this should be event of time hello world. Um, oh no, this is up here. If all works this would be sort of like the proof point that lets us it doesn't. Hello world scene. Um, >> I don't remember if this example relies on the uh, machine username, but if it does then that would be mm cal not Jonas. >> Um, maybe.
Let's just do this. Sorry, this is like the worst workshop it's and I'm also on the wrong computer. Um, it does after append. Um, hm. Okay. Is my computer back up? >> It's Yeah, but I don't know your password. >> Okay, yeah. I'll I'll do that in a second. Okay, um, this example here is not Okay, so I think we have to do plan B, but we might not actually be able to run this. >> Are you getting Getting >> I'm just going to walk through the code as we would have written it from scratch.
Sorry about that. Um, because I think it it it's sort of like illustrates the the progression of things and maybe if you it's I'm installing dependencies, which is which is slow. Uh so it's going to >> but it's like exactly. Eventually eventually this will be >> will be runnable by the end of the walk-through. >> So, um in this in this paradigm, uh as as as we we've been using it in our agent, when you want to implement some sort of feature, what you do is you say, "Okay, what is the state I actually need in in order to do my my my thing?" In this case, we want to do an LLM request whenever somebody sends a message and says, "Hi." So, um we have here in our um in our user interface, and you can access this as well, there is basically like a cheat code that makes it a bit easier to um to create uh new events of a type called agent input added.
And this is like deliberately the simplest possible thing you can imagine. This is basically just a string. And so, what we're trying to achieve is that whenever somebody puts an agent input added event into an event stream, we want to uh react to that by making an LLM request. And for uh simplicity, we're just going to go in and do it using the OpenAI SDK. So, uh the OpenAI SDK, um the way it works is um you have to uh at some point uh before you want to use it, you have to make yourself um here a new OpenAI client.
And then you can use uh their responses API. So, you have OpenAI.responses. Uh responses.create. And then uh in order to create it, um you need some information. Uh specifically, you need a model state uh string. And so, immediately there we're saying, "Okay, so let's just say our state for our LLM agent, it has a model string." Because that is one of the things that we will need when we when we come to actually make an LLM request, and there is nothing but event sourcing.
So, let's just say, "Okay, we have um we have a model string and that that comes from from um from our state." Uh and then, you know, you could easily imagine in the future, this was one of the things that you could have done as an exercise in in in the hackathon, is you you could say, let's add an event that is like LLM changed, LLM model changed, and you have the teeny tiny one-line reducer, and it just sets the model to be a different model, and then um off you go, you make the next LLM request um with a different model.
And the other thing we need is instructions. Uh this is I think a bit of a misnomer, so I would call it system prompt in our state. And we say, okay, the like the system prompt for our LLM, what it's meant to be doing, we'll take that in our state, and then you need a history. Um a state history, and um And and so we've defined this uh and normally what you'll do is uh you'll just put this into into uh like a little uh into like a little uh TypeScript type, if you're using TypeScript.
So here we're saying, this is the state of our agent. Right? And and in the beginning it's really simple, but in the future uh you can very easily imagine how how you quickly add things to it, like say, am I currently compacting, or is a tool call currently in progress, or or whatever else um you might have. Um and uh the idea is to create a system in which it is trivially easy with three, four lines of code to add one of those capabilities uh to it.
And then you say, okay, what's my initial state? Um because we're processing the stream, initially there's no events, so we need to know what we're what we're initially starting with. And so we're just saying, uh this is we're starting with an empty history and this system prompt and GPT-5.4. Um And then the next thing you do once you've um once you've done that is you need to decide, what events do I need to derive this um to derive this state?
Uh and in this case we will just um uh create a new event here. Uh a new We're using Zod here for schemas, we're saying it's an agent input added event, and it just has a string. Um and then whenever anything comes back from OpenAI, because that is like a fact that has occurred, even if it's just a teeny tiny fragment of a string or or something else, we store that in um in an event. Um And that's it. Uh the These are These are the two the two main event um event types.
Um I don't think we need any of this stuff here, actually. Basically, what happened, as is often the case, I uh I I attempted to instruct an agent to rewrite all of these examples to uh be simpler to execute just before, and it just um rewrote them quite significantly. But this is really all you need. So, um and then uh you have to write your reducer first, and the reducer is basically where you just say, "Okay, when an event is encountered, uh how do I update my um how do I update my uh state?" You say, "Okay, when an agent input added event um is encountered, this here is using a a little like Zod helper library, actually one that Misha made called Schematch.
Uh it's just uh it's it just gives you basically safety on this payload here. It says, "When I have an agent input added event, then I want to my state to be updated as the current state plus the history, except the history also gets uh this little uh this little thing here uh here appended. So, we're um and and um the the reason we're doing that is because uh OpenAI's responses API, um since we're making an OpenAI processor, we're basically translating between our view of the world, we just have this like agent input, and um it's just a string, uh but OpenAI wants you to put role user and and then put the string in a content field, so we're putting that there.
Um and um then the other thing we need to do um when you use the OpenAI streaming API, it'll it'll like basically chuck out tons and tons of these output response um events, and uh one of them finally at the very end will be um of type um uh bop bop bop bop bop um Yeah, I think I think this is a bit hogwash. Um >> entity event at the end of the day Huh? Yeah, yeah, exactly. It It basically does What we really want here is um uh um Yeah.
Oh, thank you. Um Is that actually right? Um No. Um Let's just I don't suppose you have managed to get the >> I have pushed workshop two to the >> Yeah, but it's >> the demo repo, but it's more or less as is. >> Yes. >> Yeah, let Okay, so let's let's just like uh sort of like admit defeat on the thing that I was going to do and just like try try and show you how how how it would because we we can get something like very simple working, right?
Because we have the extremely simple ping pong processor that that does work. Uh and so here we can uh we can even uh just Mm. Um Let's maybe actually start here. >> And then I hit I hit insufficient quote running my uh >> Hm. Jub jub jub. >> Yeah, we we do now have the same examples on the other repo, but it'll it'll work. >> Yeah. To be honest, I think I think we might have to just admit defeat and we can just talk about something else or give you give you the time back.
Just because the problem is we can't actually run these things. Uh and I think it will take me like probably like 10 minutes of actually concentrating to to get them runnable. Um so maybe we should uh admit defeat on that. Um I do wonder if there's like does it does Yeah, does does it does it sort of make sense what the what the idea is especially with with it being distributed? So the right that you can say, "Okay, like I have my processor over here and your agent can use it.
And it can be on a different server or it can actually be in a in a dynamic worker." Um and um yeah. I I think without showing it, it doesn't really make sense. >> So is is the idea you use um so with the stream processing, you take this event stream >> Yeah. >> from OpenAI >> Mhm. >> and it contains events like output item added I I know the output model better than I know the input. >> It's very similar. >> So and then you've got some series of like text deltas, say. >> Yeah. >> And so the reducer here is kind of squashing all of those events >> Yeah. >> and then materializing that sort of partial response >> Yeah. >> into an event, right?
So then the bit I was trying to understand was sort of with this stream processor >> Yeah. >> sort of framework that you've built is like these materialized events is are they persisted as new messages on the stream? >> Um >> Are they being the clients consume the raw events and sort of you're doing the materialization client side or is this sort of a part of something that's happening in the >> So every Yeah, so so everything that happens in the system, every streaming chunk, everything becomes a becomes an event in the stream.
And then you have reducers running in many different places. Like uh for for instance, uh you know, even this thing with like is the stream paused or is the stream not paused? The actual implementation of that is um maybe that maybe that's actually useful because this is running in production now. Uh like right like there is a a circuit breaker processor. And and this is like how the whole thing is built even inside the event servers.
And the circuit breaker processor has an initial state of paused false, and it has paused reason null. And basically and then it has a really really simple reducer um that just checks what are the last 100 timestamps of events I've seen. If the last 100 timestamps I've seen seen don't go you know, don't go more than a second back, then I'm just going to append a append an event. So, the reducer basically just accumulates these timestamps and then the after append function here says, "Okay, if I if I have seen too many timestamps in the last second, I'm going to I'm going to throw the circuit breaker." So, this is like a real processor that runs inside my my um my service.
But let me show you another one. This one here, this UI, this is also a stream processor. What does this UI do? The UI takes all of these events and for some of the events that it deems like interesting, it chucks it basically it it basically projects them onto what we call feed items. So, these things here that have like slightly nicer rendering, they are feed items and they are not the same as events, but they're derived from events.
So, when you're making UI for this thing, you're also just reducing. Um and because the reducer is just a synchronous function, right? If if if you knew for example, I have I have this like Pi agent harness processor and it comes with a whole bunch of event event types um and it has a reducer, you can just in your processor use their reducer. It's practically free, right? Like you can just import it and run it. And then you can just sort of like start building abstractions that rely on their event types.
Um and so I think what I'll what I'll what I what I will commit to doing because this was such a shitty experience is I will just do do the whole rundown in video form on the internet. And that was one of the things I was going to show. Like you can just hook up Pi or Clawed or Open Code as well. And say okay, like they come with a bunch of events and you can store them in this event stream and you can react to them or or build on them.
Um Does that answer the question like where the reducer runs? Um Um and and then like one of the things you can do with this is you can also actually just append an event that has some source code in it and then it runs that particular processor literally automatically for you horizontally scalable. Um >> It's just yeah. Do you have the example of showing how you do that where you're appending like >> Yeah, I do have that.
I do have that. I do have that. Yeah, well actually we can do it here. Yeah, I think I think I maybe maybe that is good. Just like focus instead of trying to write code we can focus on the things that might work. Um so let's we can create a new stream. By the way, all streams are created you know completely implicitly so you can just post to anything under the streams API and it'll it'll make you a new stream. And then here there's in the UI and you can also play with this if you want to just see there's a there's a bunch of sort of preset um preset events and one of them is here.
You can append an event of type dynamic worker configured to this thing. And what does it have? It just has a script in it and the script is a string and inside the string is a reducer and an after append hook. And so this is um literally a uh like a stream a stream processor. It would be funny if this if this is the thing that works because this is I was basically I was basically most of the night working on this because this is the most exciting bit but it wasn't really like workshop grade because it was you know, you get to get like the first five concepts and then you're like by the way, you can deploy this by just adding an event.
Um but if I if I just say ping here it says pong, right? That's pretty crazy. Like I have here a stream that knows nothing about the world and then I have appended this event here that just has a little bit of JavaScript in it. And this little bit of JavaScript uh just makes it respond with pong whenever it encounters something with ping. And then there is actually a a version of this. This is the thing that actually took took the night away, so to speak, is if you have these processor files that export a processor that you define with define processor, you can bundle that into an event effectively.
And this AI agent, I also got running like that. But of course you don't want to have your OpenAI API key in there. So that is why we have this like slightly awkward enforce here, where you can put your OpenAI API key outside of the stream, and then um it will basically, when it makes a fetch request, it'll substitute the secret in in the header. But um Yeah, I'll definitely I'll definitely post a video of that, because that's that's pretty wild.
Like you you can write like the 40 lines of code required for basic AI agent, and then you can append that to any stream, and then that stream becomes an AI agent. I don't know. I'm sort of looking at like two or three nods, but mostly blank blank stares. It is very strange. Um But uh but but I think does this does this make sense what happened here at least? Because you can This one you can just play with. Like you can just go in the UI.
And so uh to some extent uh actually you can uh you can make increasingly more complicated processors for your streams. Uh you can just you can just code them in this input field if you want. Or uh you know, um the only problem is it cannot have any dependencies. Like if you want to NPM packages, you have to bundle it into this string, which gets a bit more complicated. But um Yeah. Yeah, so this is the other thing. Like everything that you you might have noticed is everything has a slug.
It's just like a URL safe identifier. And so the the event here is actually called dynamic worker configured because you can override it. And And what also already works with this event type is you can give instructions to an AI agent to make itself different functionality just by calling append um with like a little bit of a different JavaScript um and uh you know you you could you can quite easily imagine overcoming the bundling problem for example by just saying oh there's another event type which is called like uh sort of like uh unbundled uh dynamic worker which just has a package.json file a field and a script field and then a different processor takes it bundles it makes the fat event that has all of the bundle source code and suddenly uh is is basically like a like a IDE and and that's then where you can you can hack on the agent harness without having to really like install anything or like bring servers into the mix or or whatever um but sadly was not able to show it so bummer >> What if what if there is an error in the in the JavaScript or you put it in the stream? >> hm? >> So if you push the >> JavaScript code in a stream and if there is an error in that code or if you made a >> uh >> typing error what happens then? >> uh well this this is uh this is uh JavaScript there wouldn't be a typing typing error um but it uh if there's any kind of error the only thing that can possibly happen is that you get an event so there would have to be an error event um >> and there's no there are no typing errors as implemented right now but you that's because this is a JavaScript evaluator but you could also find a way to run a TypeScript compilation step on it first and then you could emit errors saying there was a TypeScript compiler error then you could run it through an LLM to try and fix it and emit a new event with the fixed code or do something else with it >> um >> the idea is that just everything that happens results in an event and then you can react to those events however you you see fit >> and then the number one >> Do these events data then evaluated and run in your back end, right? >> Yes, so in this particular case, it's it's dynamic workers in Cloudflare.
So, it it just spins up a small small dynamic worker. Um so, basically, like the deployment story for processor like this is or or like one way to think about it is uh at what when when this was still working before I asked it to be refactored and broken, I had um the way I would do it is I would locally on my computer, I would do the SSE subscription and and run my processor that way. And then, once I thought it was cool, uh I could either deploy it just as a web service on on Cloudflare workers or Vercel or or wherever uh and and just tell uh tell the um agents uh uh the tell the streams to notify me whenever a new event needs to be processed or uh alternatively, it just use this dynamic worker thing.
Um and like this I don't I don't know if this is going to work. This is why I like at the moment, it's looking more like it's a really dumb idea, I think, because it's really not coming across. But, the For example, you could have a plugin for your agent uh that runs on another computer, especially if it was like something like really important like a prompt injection protection or something like that, right? Like you could say, "Oh, okay.
The way that my agent uses your prompt injection protection service, it can't really be through MCP because there's no way to to kind of like proactively hook into the agent loop or or um at least not at the minute. But, what it could be is it could say, 'Okay, my my agent loop actually waits for up to like 200 milliseconds before making any new LLM request uh for any safety checkers to say that.' And then, you can just literally ask your safety checker over there.
I don't care how you implement it. You could even charge me for it, right? Um and I just don't Yeah, I just don't think that's uh currently possible in in any other way. That's why I think it's quite important that the stream can reach out to the processors and say, "You got to do something, you know? You need to process some events now." Um Um there's a there's like a couple other uh potentially Mm, I don't I mean, it's my >> Yeah. >> One of the ideas we shared is uh my agent might use just-in-time services of other agents offering. >> Yeah. >> And he might be charged for it. >> Yeah.
Well, I mean like probably in initially the human would be charged of it. But But this is just like there there is no way like let's say okay, so Claude code if I want to make a Claude code plugin um if if I wanted to make that into a business, think think about how you would have to do that at the moment. And you need to give some sort of instructions or or something to to to Claude code either to proactively call your MCP tools or or something of that nature or call maybe some CLI tool that was previously authenticated where you did like CLI login to you know like prompt injection protector.com and then somehow it works where whereas um uh really I think you can just plug into the into the agent stream like into the event stream directly.
Like the the interface is just somebody somebody notices that Claude is about to do something and chuck some more events in. And And like they kind of all work that way but not quite. Like it's it's sort of like you have to squint a lot to to see that that's what it all compiles down to um Another thing maybe worth pointing out if for some of you that have tried to like try to make open code or or or pi plugins or whatever is there's no before hook.
This is very very important. There's no like there is actually in the back end like our built-in processors the only difference to our processors and your processors is that we can actually stop events from ever being appended. For example that is why the pause feature could not be implemented by a third party. So there's a sort of like certain things that are just um that that need to happen before an event goes in the stream.
But um broadly speaking I'm very against before hooks. Like I think there were some instances in in open claw for example some massive performance regressions and and cost increases where you know you can you can break uh you can break context caching quite easily with before hooks. You can massively destroy performance. I guess it's way better to think of the whole system as as being eventually consistent. And you know, doing all these distributed systems things like saying, "Okay, we're going to wait for up to 200 milliseconds for somebody to say I've got a little bit of information for you, but then we're actually going to make the LLM request whether you come in with information or not because this is needs to be resilient system.
So, if you think for example about rag pipelines and and things like that, you can easily have a little processor that says, "I have like a index version of the Notion knowledge base or something, and I'm just going to sit here and try to squeeze in a little bit of extra context if I think it's relevant, but if I don't get there in time, it's like totally chill. The whole thing still works. It's not like I've I've kind of delayed the the agent or something." Um yeah. >> What about the So, you're also listing this this instance of each rate.
Like, how would you imagine in the future everyone has their own one or two >> You mean I mean, the the the the the streaming database. Like, I don't know. I I I I think um I think this could work on almost anything that is like durable stream shape. So, this was just for the purposes of this um exercise. Uh I do think like there is a potentially an interesting scenario where like where like It's It's not even really like it's combination of a queue and a pub sub system and a and like a streaming database and uh that can also run code for you, but but that that sort of thing is an interesting infrastructure primitive that maybe somebody could make.
Um I do think that yeah. But in principle, like I I don't know if if you don't know about it yet, you can read up on this durable streams API specification that somebody came up with. We don't follow it exactly, but uh close enough, and it's it's basically like a like a very common old idea. Like um The the thing that is more new is that it would be like you would also have push subscriptions out of it. But there are some things that do is there's a thing called NAT like Jetstream NAT or something that that does it.
Um Yeah. >> Are you talking about like the electric sequel? >> Yeah, exactly. They they have durable streams, yeah. And like a durable stream is just like an append-only event log with with offset tracking. And and the you know, they want the client to track the last consumed offset. That's also how say Kafka works or something like that. But you can also do it the other way around and have the server track the offsets.
And those are more more normally like there's Google Cloud and AWS they have these pub/sub systems where they say, "Oh, we'll just like give you the next event and we'll keep track of of the offset for you." Um >> I have one other question. >> Yeah. >> All right, say you say you have got a I've I've got my ability or my and I have a sub particle images and I hook it up to like a local LLM which is generating images and then anyone could essentially pass a stream to that which would then go to my LLM generate an image and return it back. >> Yeah. >> How would I like prevent a certain amount of like basically flooding with requests and >> Oh, I mean you would need to have authentication on it.
Right right like this this entire thing would never like right like this I was thinking like it might be fun to just say there's a there's that yet basically. Yeah, exactly. It might be fun to just say there's a public namespace and it just gets cleared every hour or something, right? Because it is kind of nice that anybody anywhere on the internet can just curl a thing or like copy and paste a curl from somewhere and and then suddenly have like a flavor of agent.
I do think that's quite interesting, but it just needs to be deleted every like quite aggressively. Um Yeah, but but I think I think that's more or less a solved problem. It's like a bit gnarly, but basically the way I envision it you would do it if you did this properly is on each event you basically have like client provenance information. We say like who was this? Like what were they able to do? Like how how sure are we that these people are you know, that the HTTP client or the the stream client was actually entitled to do this operation.
Um And and again, you can model all of that as events. Right? Like you can you would just have an event that is like make this stream public. And until you make that event, it can only be uh written to by whoever created it or something. Um All right. I might ask uh um uh Sean if we can instead of this video, do a video we'll record a little bit later today um that shows it more nicely cuz I do think it's worth showing.
It's just a little bit too short short notice. So we just wrap it then if uh I don't I don't mean to keep you all of you uh like 10 minute late longer break. If anybody wants to chat. >> Thank you.
The words are the caption track's own and nothing is reworded or re-transcribed. Paragraph breaks are placed between sentences so the text reads as prose.
Free tools for your own script. No signup, no login.
Paste your draft and see where viewers are likely to drop off, with a rewrite for each weak line.
Paste the first 30 seconds of your own draft for a hook score and rewrites.
Check your draft against YouTube's advertiser-friendly guidelines before you record it.
Read this channel's public videos and transcripts, and download a writing brief for it.