Transcription: OpenAgents Episode 009 - Building the UI
June 9, 2026 ยท View on GitHub
Source: https://twitter.com/OpenAgentsInc/status/1723164712957862115 Wiki source: https://raw.githubusercontent.com/wiki/OpenAgentsInc/openagents/Video-Series.md Media title: OpenAgents - Episode 009: Building the UI We implement our wireframe mockups in cod... Upload date: 20231111 Transcription model: gpt-4o-transcribe-diarize Generated at: 2026-06-01T01:28:34Z
Machine-generated transcript. Review speaker labels and wording before using this as quote-grade source material.
[00:00] Christopher David: Alright, so we're building the UI for this. I built part of it. I had this PDF widget thing in a different code base.
[00:10] Christopher David: So we've got the homepage.
[00:13] Christopher David: That looks fine.
[00:14] Christopher David: I just put see what's cooking so we don't imply that it's ready because this is live, I think.
[00:20] Christopher David: Oops.
[00:22] Christopher David: Yeah.
[00:27] Christopher David: You click start,
[00:28] Christopher David: boom,
[00:29] Christopher David: you drop a PDF,
[00:30] Christopher David: pretty simple,
[00:32] Christopher David: and you can either click on it to open up the widget thing there or you can drag a PDF on there.
[00:41] Christopher David: Haha,
[00:42] Christopher David: it says feed me.
[00:45] Christopher David: And then as soon as that upload finishes,
[00:49] Christopher David: it will swap out the widget.
[00:53] Christopher David: that interface see we're staying on the same page and we're going to say you know the very basic chat widget and I wanted you to join me for this so people that are going to be interested in editing our chat UI
[01:11] Christopher David: uh can see me start to work with that because this is something that we're going to have multiple other developers helping to build out we've already awarded a few million sats worth of bounties to people working on this mostly trigger who's done a great job kind of adding a little nice little animation on the sidebar thing here um and so in this video we're basically just going to pull over this this is all that we want and we had already harvested this from the like chat
[01:40] Christopher David: What was it? The Vercel chatbot thing there.
[01:46] Christopher David: Just because they had a good, yeah,
[01:53] Christopher David: they had this clean,
[01:55] Christopher David: nice,
[01:55] Christopher David: I think it even uses Shad components that we had pulled over to the JupyterTopia website.
[02:01] Christopher David: We're just going to pull that in to here.
[02:04] Christopher David: So a quick review of other things that we've done already.
[02:10] Christopher David: I had originally had the upload file endpoint
[02:15] Christopher David: behind the auth middleware that requires you to be an auth user.
[02:21] Christopher David: But I actually,
[02:22] Christopher David: you know, we didn't put any authorization authentication flow in here and I don't want that.
[02:30] Christopher David: I find it really annoying when I want to like kick the tires on a new service to see if it works to have to like create an account first.
[02:37] Christopher David: verify my email it's like right now I just want to let people as quickly as possible test to verify that something cool actually happens so at least for now you don't need to authenticate in order to do a file upload and we created tests for that for both making sure that both auth users and unauth users can upload a file via API and then we may change that later on to unauth user cannot upload a file
[03:04] Christopher David: Um,
[03:05] Christopher David: but our tests are passing and you can always kind of, whenever you're coming into an application that has thorough test coverage like this one does,
[03:12] Christopher David: um,
[03:13] Christopher David: you can run the tests or look at the tests and see,
[03:15] Christopher David: oh,
[03:16] Christopher David: like here's all of the functionality that this app has.
[03:20] Christopher David: Cool.
[03:23] Christopher David: Uh,
[03:23] Christopher David: and then what else? I did the, um, the Laravel installation for the Shad UI components.
[03:30] Christopher David: So we now have the ability to pull in Shad UI components and we so far have under resources JS components UI we have the alert button card input and label components and you can see that all right there.
[03:52] Christopher David: So let's pull in some chat UI.
[03:56] Christopher David: um i just love how there's there's just no bullshit here it's like you upload a pdf boom and then you're gonna be chatting with it i think in the next video we will go into the logic of what actually happens to the pdf i'm pretty sure i want to integrate with a third-party service uh that's really great at like taking a pdf and then letting you do a retrieval augmented generation or rag over it
[04:25] Christopher David: Um,
[04:26] Christopher David: but it should be as simple as you throw in a PDF, then you can chart that. Uh, then we can do cooler.
[04:31] Christopher David: Cooler things once that little core building block is solid.
[04:36] Christopher David: So right now,
[04:38] Christopher David: we
[04:40] Christopher David: have a little placeholder here that says if the file, if there's a file name that we get back in the sort of flash properties of inertia after the file upload.
[04:51] Christopher David: Then it'll show a chat interface. And let's do this as a separate component. So we'll call this uh
[05:03] Christopher David: Let's just call it chat.
[05:09] Christopher David: Uh let's put this here.
[05:13] Christopher David: And make some changes so we know that it works.
[05:39] Christopher David: Do I need to reload?
[05:48] Christopher David: Oh.
[05:54] Christopher David: I guess I should actually return it.
[05:56] Christopher David: Chat will go here. Okay. So let's take a spin through our GPU to GPUtopia code base.
[06:03] Christopher David: That's on our website currently.
[06:08] Christopher David: and
[06:14] Christopher David: Oh great, and there.
[06:17] Christopher David: What was here?
[06:19] Christopher David: Can I read properties of null reading ID? That's not good.
[06:28] Christopher David: Well, you saw it streaming for a second there.
[06:40] Christopher David: Well,
[06:40] Christopher David: something's broken there,
[06:43] Christopher David: but the cool thing is that we have this inference is coming from our swarm network of GPUs. Nice little sidebar.
[06:54] Christopher David: Does regenerate work?
[06:58] Christopher David: Nice.
[07:03] Christopher David: Yeah,
[07:03] Christopher David: streaming from our swarm network of GPUs. That's pretty cool. I'm pretty sure this is using...
[07:09] Christopher David: It's either using Vicuna. It was originally using Vicuna. I think we might have swept it out to Mr.
[07:13] Christopher David: Hunter.
[07:15] Christopher David: But it's cool to see this evolved without me having been in the code base.
[07:20] Christopher David: So this is in chat page.
[07:24] Christopher David: I'm looking forward to getting away entirely from the next JS way of doing things.
[07:33] Christopher David: And they're using all of this.
[07:36] Christopher David: AI library that I don't think we're going to use at all.
[07:42] Christopher David: But what I want is the
[07:48] Christopher David: chat list.
[07:52] Christopher David: Maybe I'll start by pulling over all of this.
[07:59] Christopher David: Oh wait, let me make sure I have the latest changes.
[08:08] Christopher David: Let's pull this over.
[08:25] Christopher David: Something has messed up my autosave.
[08:32] Christopher David: Now what do I need here?
[08:39] Christopher David: ContainerRef
[08:54] Christopher David: And then for messages,
[08:56] Christopher David: let's start with just hard coding an empty array.
[09:11] Christopher David: C_N_ is not defined.
[09:13] Christopher David: We need to get that from
[09:16] Christopher David: lib utils.
[09:20] Christopher David: Something is also messed up with my editor, because I'm not getting the
[09:28] Christopher David: I don't know, maybe I'm just used to T_S_X_ components m have more red squiggles.
[09:34] Christopher David: J_S_X_ does not.
[09:37] Christopher David: And class name
[09:40] Christopher David: Oh, I need all this stuff down here.
[09:46] Christopher David: What does this have for class name?
[09:56] Christopher David: Why are we passing in class name?
[10:03] Christopher David: That doesn't seem to make any sense there.
[10:13] Christopher David: Keep it simple, stupid.
[10:18] Christopher David: I think for now, so I don't have to keep uploading
[10:25] Christopher David: a file, I'm just gonna say place holder there.
[10:38] Christopher David: Okay, empty screen is not defined.
[10:46] Christopher David: That's...
[10:48] Christopher David: I can put there.
[10:57] Christopher David: Chat panel is not defined.
[11:06] Christopher David: Oh, here's where we get into all this other stuff.
[11:16] Christopher David: I do want prompt form.
[11:31] Christopher David: I don't want that. I don't want update balances.
[11:36] Christopher David: I don't want footer text. I don't want A_I_ react.
[11:42] Christopher David: I want to update this.
[11:44] Christopher David: And this, this is my red squiggles. I love you, TypeScript. I love you.
[11:52] Christopher David: Use chat helpers. Yeah, that's from that AI library that we are not going to have.
[12:22] Christopher David: Okay, buttons scroll to bottom, that seems worth stealing.
[12:28] Christopher David: We can steal for ourselves.
[12:31] Christopher David: Let's see.
[12:35] Christopher David: Remove this use client bullshit.
[12:39] Christopher David: Button
[12:44] Christopher David: And then let's see about this icons thing.
[12:48] Christopher David: Components.
[13:03] Christopher David: Alright our button scroll to bottom seems to be working.
[13:10] Christopher David: And we're gonna get that from right here.
[13:23] Christopher David: Don't do any!
[13:25] Christopher David: Any!
[13:27] Christopher David: There's just a bunch of other stuff that we're going to have to strip out from the dependencies from the Vercel AI.
[13:42] Christopher David: I think that Vercel AI package,
[13:44] Christopher David: it might work with what we're doing.
[13:47] Christopher David: We'll have to re-familiarize ourselves with that.
[13:50] Christopher David: I just want to get to see some little pretty
[13:57] Christopher David: something on the screen.
[14:00] Christopher David: Next navigation lol.
[14:04] Christopher David: Alright, this is the main thing we gotta clean up.
[14:16] Christopher David: Lib hook use enter submit.
[14:18] Christopher David: That seems fun.
[14:26] Christopher David: Or would I put hooks over here?
[14:33] Christopher David: Lib.
[14:36] Christopher David: That looks good.
[14:42] Christopher David: Let's see if I can find it. Yeah.
[14:51] Christopher David: Alright,
[14:51] Christopher David: I think we need tooltip.
[14:53] Christopher David: as a shad component, so I'll show you how I put that in.
[15:02] Christopher David: Go to
[15:04] Christopher David: components,
[15:06] Christopher David: tooltip,
[15:09] Christopher David: install, N_P_M_ is what we're using.
[15:18] Christopher David: There it is, it added it.
[15:21] Christopher David: Right there.
[15:26] Christopher David: And I think it will have installed that react dash tooltip as well.
[15:34] Christopher David: Yep.
[15:37] Christopher David: All right, so I just need to update that and that and that.
[15:44] Christopher David: Okay, text area auto size, that seems like something we need to install.
[15:53] Christopher David: And how are we using uStore here? Balance.
[16:01] Christopher David: Does not matter.
[16:17] Christopher David: ID is not defined.
[16:28] Christopher David: He's like okay,
[16:28] Christopher David: I need to do all these things
[17:07] Christopher David: preview token.
[17:12] Christopher David: I don't know what that is. Okay,
[17:14] Christopher David: we got something on screen.
[17:18] Christopher David: Oops.
[17:21] Christopher David: Okay.
[18:04] Christopher David: Okay, a little placeholder there.
[18:20] Christopher David: Alright, let's have this text area not be so ugly.
[18:54] Christopher David: Looks good there, doesn't that look good here, why?
[19:57] Christopher David: Out of curiosity.
[20:01] Christopher David: Append is
[20:30] Christopher David: I don't even have chatless pulled in.
[20:43] Christopher David: Okay,
[20:43] Christopher David: how do I not have this be so smudged?
[21:04] Christopher David: Do I need to put it in a H
[21:08] Christopher David: screen?
[21:28] Christopher David: I don't know that I need that scroll to bottom button.
[21:34] Christopher David: Uh, this text area is kind of pissing me off. Let's see what we can do about it.
[22:12] Christopher David: Okay, I got rid of that ugly gradient.
[22:17] Christopher David: Now, the text area.
[22:44] Christopher David: What is adding
[22:48] Christopher David: a border to this?
[22:58] Christopher David: Outline none, 2px solid transparent.
[23:08] Christopher David: I guess that's just a spacer.
[23:22] Christopher David: This might be it.
[23:25] Christopher David: Yeah.
[23:27] Christopher David: Where is this coming from?
[23:35] Christopher David: Type text where
[23:39] Christopher David: it's not these various types.
[23:46] Christopher David: Comma text area.
[23:53] Christopher David: It's coming from app.css,
[24:00] Christopher David: probably one of these tail-end things.
[24:09] Christopher David: Can I do,
[24:13] Christopher David: or was I just?
[24:39] Christopher David: Border with zero important.
[24:43] Christopher David: Just because I don't want to actually track down where it is.
[24:53] Christopher David: Did that do it?
[25:00] Christopher David: Okay, but now we still have this focus.
[25:49] Christopher David: Come on, co-pilot, help me out.
[26:19] Christopher David: Oh yeah!
[26:21] Christopher David: Thank you, Copilot.
[26:24] Christopher David: Okay, that feels not horrible.
[26:37] Christopher David: Very nice.
[26:40] Christopher David: Except why is this kind of like down a little?
[26:48] Christopher David: Four. What's top four?
[26:52] Christopher David: Is this needed?
[27:10] Christopher David: Top four, why?
[27:15] Christopher David: There.
[27:27] Christopher David: And now it's not centered.
[27:37] Christopher David: Well, looks like that on the other one too.
[27:48] Christopher David: It should be flush up against the bottom.
[28:08] Christopher David: Sticky, bottom zero, p_b_ four.
[28:17] Christopher David: Why is it p_b_ four?
[28:19] Christopher David: Shouldn't it be p_b_ zero?
[28:24] Christopher David: p_b_ two.
[28:29] Christopher David: Okay.
[28:31] Christopher David: We don't need to get Pixel Perfect there.
[29:34] Christopher David: Okay, so that's a nice little uh typing experience. I actually like enjoy using it.
[29:42] Christopher David: Let's get the messages working.
[29:47] Christopher David: And yeah, we're not gonna use the
[29:50] Christopher David: open A_I_ thing. We're just gonna kind of build our own handling of messages.
[29:58] Christopher David: For example, let's do uh cons messages, set messages equals rack you state and then let's append that to there.
[30:12] Christopher David: Now it's gonna freak out that we don't have a chat list.
[30:20] Christopher David: So
[30:26] Christopher David: let's grab the chat list.
[30:36] Christopher David: Chat list. Don't need that.
[30:39] Christopher David: I
[30:44] Christopher David: I don't know what that's gonna need to be.
[30:51] Christopher David: Uh, looks like we're gonna need a separator.
[30:54] Christopher David: First let's grab chat message.
[31:07] Christopher David: Okay, now we got a bunch of stuff. We got the remark stuff for markdown, blah-di-blah. Hopefully we can just copy pasta stuff over so it works. Ooh, components ui code block.
[31:19] Christopher David: Is that from shad too?
[31:21] Christopher David: Hopefully it is.
[31:24] Christopher David: Uh, it's not.
[31:26] Christopher David: Code block.
[31:28] Christopher David: Where did we get that from?
[31:31] Christopher David: I don't know.
[31:34] Christopher David: But through the magic of copy paste.
[31:41] Christopher David: Use copy to clipboard.
[31:50] Christopher David: I think we will put our
[31:53] Christopher David: hooks in the hooks folder of that.
[32:06] Christopher David: And the other one was use copy something.
[32:09] Christopher David: Use copy to clipboard.
[32:12] Christopher David: grab that man
[32:17] Christopher David: all those used clients sprinkled everywhere because we used normal react hooks was super annoying
[32:39] Christopher David: all right chat message that's in the same folder
[32:42] Christopher David: And let's see if we can just add separator like this.
[32:54] Christopher David: Cool. And chat message. We're not doing AI.
[33:06] Christopher David: Code block hopefully works.
[33:09] Christopher David: Chat message actions.
[33:23] Christopher David: Just going to pull all that stuff in here.
[33:39] Christopher David: Okay.
[33:44] Christopher David: Alright, we mark G_F_M_ and we mark math.
[33:53] Christopher David: Those tend to be things where I wanna use the exact version numbers as what I pull them from.
[34:00] Christopher David: So I don't have to think about it.
[34:11] Christopher David: And then add components markdown.
[34:15] Christopher David: React markdown.
[34:20] Christopher David: I'll put that in the same place for now.
[34:23] Christopher David: I will also get react markdown from there.
[34:45] Christopher David: Okay, that looks good. This will grab for the local.
[34:51] Christopher David: No red errors.
[34:54] Christopher David: Nice.
[34:59] Christopher David: Looks good, looks good,
[35:03] Christopher David: looks good, looks good, looks good.
[35:09] Christopher David: Looks good.
[35:12] Christopher David: What is airing now?
[35:16] Christopher David: Use enter submit.
[35:23] Christopher David: Do we need to recompile because we changed the path on a file?
[35:32] Christopher David: Chat list is not defined. That's easy because we just need to import it.
[35:39] Christopher David: I don't know what chat scroll anchor is. Let's try removing it for now.
[35:45] Christopher David: Okay, React syntax highlighter needed by the code block.
[35:55] Christopher David: Does that need configuration?
[36:26] Christopher David: Okay, so we have a
[36:31] Christopher David: copy-paste works too.
[36:36] Christopher David: Regenerate. I don't want it to say regenerate.
[36:46] Christopher David: That's cool.
[36:48] Christopher David: I just don't want it there.
[36:57] Christopher David: Now I don't want it, why is it all centered?
[37:47] Christopher David: Item center, justify center.
[37:49] Christopher David: No,
[38:12] Christopher David: that's for the icon.
[38:15] Christopher David: I don't want this to be centered. Why is it centered?
[39:44] Christopher David: Okay.
[39:46] Christopher David: Um what does this border do?
[39:53] Christopher David: I might wanna remove this border here.
[40:08] Christopher David: D separator.
[40:45] Speaker B: Huh?
[41:01] Speaker B: What's underneath the group?
[41:14] Speaker B: separator.
[41:17] Speaker B: What if I don't want a separator?
[41:23] Speaker B: Or what if I want the separator to be
[41:31] Speaker B: Oops.
[41:40] Speaker B: Just the spacing without the
[41:43] Speaker B: Okay.
[42:06] Speaker B: Uh not it.
[42:07] Speaker B: Now I need to make it not be 600 on one and different on the other.
[42:39] Speaker C: Okay.
[42:46] Speaker B: What happens if it gets down too low?
[42:56] Speaker B: That's gross.
[43:01] Speaker B: I'm guessing there's a hook for like auto scroll.
[43:09] Speaker B: Use at bottom
[43:29] Speaker B: Oh, I'm guessing that's what the chat scroll anchor is for. Let's see if we can get that to work.
[43:35] Speaker B: React Intersection Observer and
[43:54] Speaker B: then use at bottom.
[44:16] Speaker B: Go chat panel
[44:18] Speaker B: or
[44:21] Speaker B: here.
[44:27] Speaker B: What does that do?
[44:37] Speaker B: Okay, I thought that might go to the bottom.
[44:46] Speaker B: Entry, target, scroll into view. Use at bottom.
[45:09] Speaker B: What did I see was hard-coded as false somewhere here.
[45:18] Speaker B: Button scroll to bottom. And then where was that?
[45:28] Speaker B: What does that do?
[45:42] Speaker B: Okay, that scrolls to bottom.
[45:47] Speaker B: But
[45:51] Speaker B: What's it supposed to look like?
[45:58] Speaker B: Oh, it's supposed to be over there.
[46:02] Speaker B: But I guess that's not what's tracking.
[46:32] Speaker B: curiosity.
[46:35] Speaker B: I don't know why that's commented out. Does it work?
[46:47] Speaker B: Uh maybe 'cause it doesn't seem to work.
[47:00] Speaker B: True true true true true true true true true. Right now it should say false.
[47:06] Speaker B: And it's not. So something is wrong with that.
[47:12] Speaker B: Why is something wrong with that? I don't know why something is wrong with that.
[47:28] Speaker B: I don't want a button to scroll to the bottom. I can tell you that. I don't think it's necessary.
[47:34] Speaker B: I do want it to auto-scroll to the bottom when
[47:38] Speaker B: a new message is appended.
[47:41] Speaker B: I would like to know what over here does that. I'm gonna spend a maximum of thirty more seconds on this. If is it bottom and track visibility and view
[47:57] Speaker B: Okay.
[47:57] Speaker B: That is a problem for another day.
[48:04] Speaker B: Um so the goal here was to do
[48:10] Speaker B: a chat UI. And we have it. Uh let's do one more thing.
[48:15] Speaker B: Let's remove the hard-coded
[48:22] Speaker B: file name.
[48:32] Speaker B: Okay, so now
[48:43] Speaker B: Okay, we have a chat UI.
[48:45] Speaker B: We are ready to connect this to our documents
[48:51] Speaker B: and
[48:55] Speaker B: we'll fix the scroll thing later.
[48:57] Speaker B: which is more tied to like the actual responses that we get back from the servers. We'll want it to scroll down.
[49:04] Speaker B: Um no problem.
[49:07] Speaker B: So let's push this up so people can play with it if they want to.
[49:11] Speaker B: Good for now.
[49:13] Speaker B: Oops.
[49:24] Speaker B: Okay.
[49:25] Speaker B: We have implemented our UI as we've designed it.
[49:33] Speaker B: Let's even maybe see if we can test it on openagents.app.
[49:38] Speaker B: Let's see if it works.
[49:40] Speaker B: Boom.
[49:41] Speaker B: Upload a PDF.
[49:44] Speaker B: Chat will go here. That's not our latest code.
[49:49] Speaker B: Is it still uploading?
[49:54] Speaker B: Let's see if there's an error.
[49:57] Speaker B: Deploying. One alert.
[50:04] Speaker B: Oh.
[50:05] Speaker B: Got some type errors.
[50:08] Speaker B: Let's clean up after ourselves.
[50:11] Speaker B: And to replicate this on localhost,
[50:15] Speaker B: we're going to do this.
[50:20] Speaker B: And smash these type errors real quick.
[50:24] Speaker B: In code block.
[50:28] Speaker B: Copy to clipboard.
[50:35] Speaker B: Oh, it doesn't like that.
[50:37] Speaker B: It doesn't like that.
[50:41] Speaker B: I don't know why that's commented out.
[50:45] Speaker B: Do we have lib hooks copy to clipboard? Yeah, we do.
[50:55] Speaker B: And lastly, prompt form.
[50:58] Speaker B: Let's just remove that.
[51:05] Speaker B: And we'll unfortunately do that as any.
[51:22] Speaker B: We'll clean up all these types later.
[51:25] Speaker B: Or never.
[51:34] Speaker B: Looks like that's building.
[51:40] Speaker B: I can see our start page has a megabyte of, I guess it's uncompressed, 300 K of compressed J_S_ It's a little heavy, but
[51:50] Speaker B: not too bad.
[51:56] Speaker B: Deploying.
[51:58] Speaker B: Let's see if it goes through.
[52:13] Speaker B: Looks like it did. So I'm going to open agents dot app.
[52:17] Speaker B: Let's see what's cooking.
[52:20] Speaker B: Ooh, upload a PDF.
[52:21] Speaker B: Create your first agent from a document.
[52:24] Speaker B: Let's upload a document.
[52:29] Speaker B: I have uploaded a document.
[52:31] Speaker B: Now, this doesn't work yet, but how cool would it be if it does?
[52:38] Speaker B: Alright. We have a UI.
[52:40] Speaker B: It implements uh our spec one hundred percent.
[52:45] Speaker B: Uh you know except for the actual message call, we're just kind of simulating that.
[52:50] Speaker B: But in the next video we're going to handle the logic of interacting with our PDF so
[52:58] Speaker B: we can actually ask it meaningful questions and get meaningful responses.