AI Engineer World's Fair 2025
How agents broke app-level infrastructure
Read the talk
How agents broke app-level infrastructure
As prompts become long-running workflows, compute must outlive browser connections, preserve progress, and recover from failures without making users start over.
From a talk by Evan Boyle
Before you start: Familiarity with TypeScript, HTTP APIs, and background jobs will help; the article explains the Redis Streams mechanism as it appears.
From prompts to data pipelines
What happens to the compute layer when a simple prompt grows into a data pipeline? Evan Boyle approaches that question as GenSX’s founder and CEO and an early Pulumi employee. His diagrams were generated with GPT-4o, accompanied by a warning about its spelling. The infrastructure problem starts with something equally familiar: a prompt and a few tool calls—enough, he jokes, to raise a ten-million-dollar seed round.
Turning that prototype into a reliable product means controlling more of its behavior. Instead of leaving everything to one nondeterministic interaction, developers chain tailored prompts, write evals against them, and manage the context each receives. Boyle illustrates the resulting runtime growth as thirty seconds becoming a couple of minutes. Eventually, context becomes the larger engineering problem: crawling a user’s inbox or ingesting GitHub code creates substantial additional LLM processing. Improving the agent has also turned the application into a data pipeline.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Longer requests, unreliable dependencies
The old request model assumed a short trip through an API and database. Boyle contrasts a conventional web response taking a few tens of milliseconds with an AI response taking a couple of seconds at best, conditional on a fast model or prompt-cache hit. He calls the latter “P1,” without defining the statistic. A delay that once might have paged the on-call engineer is now part of the expected product experience. Infrastructure designed around short requests inherits the wrong assumptions about how long work stays active.
Longer execution also leaves more opportunities to encounter dependency failures. Boyle walks through a Slack channel subscribed to provider incidents: one outage lasts roughly an hour and resolves by 10 PM, then trouble returns at 1:20 AM and remains at 4 AM. He challenges a displayed 99.9% uptime figure by pointing to yellow and red status-history bars, and reports that a Gemini outage overlapped the illustrated OpenAI outage. The example makes failover less reassuring: another provider is useful only if it is available when needed. The displayed history does not establish a comparable availability measurement across providers.
Even when providers are healthy, onboarding customers or processing document batches produces bursty demand. Boyle describes high usage tiers as a spending barrier to experimentation, saying Tier 5 required thousands of dollars. That historical figure should not be used as a current requirement: the OpenAI rate-limit documentation, checked in August 2026, lists $1,000 paid for Tier 5 qualification. Qualification spending, monthly usage ceilings, and model-specific request or token throughput are separate constraints. The engineering problem remains absorbing bursts without treating every rate-limit response as a failed user operation.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
The gap between a chatbot template and a workflow engine
A Next.js chatbot template makes the first version easy. Once its work lasts minutes or hours, the full-stack engineer inherits problems traditionally handled by data infrastructure. Existing tools offer several starting points:
| Tool | Starting point |
|---|---|
| SQS | Queues around which to assemble orchestration |
| Airflow | Batch-processing workflows |
| Temporal | Durable execution |
Boyle’s objection is partly about developer experience. As a TypeScript and full-stack developer, he would rather retain the simplicity of serverless than assemble a queue-based orchestration system. His joke about avoiding tools designed by Java engineers expresses that preference, rather than a technical evaluation of those tools.
Serverless introduces its own constraints. Boyle describes five-minute timeouts and, on some platforms, limits on outgoing HTTP requests. He also describes streaming as work bolted onto the application. These are not universal platform properties: Lambda supports execution timeouts up to fifteen minutes, and native Lambda response streaming arrived in 2023 through function URLs and its invocation API, with integration restrictions. Streaming a response and preserving a reconnectable history are different capabilities. A user refreshing a page during a long operation needs the latter, even if the platform already supports the former.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Let users start before ingestion finishes
Website onboarding makes the lifecycle problem concrete. The user supplies a URL, and an initial LLM call extracts information from that page and identifies other pages to scrape. That first interaction starts a much larger background operation. In Boyle’s example, scraping and enrichment take multiple minutes and involve hundreds of LLM calls.
The product should become usable while that work continues. Boyle presents a ten-minute onboarding wait as a risk to funnel completion, not as a measured conversion result. Moving ingestion into the background removes the wait, but creates a communication requirement: show its status inside the product. Users need to understand that more data is arriving and that the experience will improve as enrichment progresses. Background execution and visible progress are therefore parts of the same onboarding design.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
A writing agent makes progress part of the product
The second product example generates a blog post about building high-performance web applications with Vercel and Next.js. It tells the user up front that the operation will take a couple of minutes. A progress panel then exposes the work: research, outline generation, and writing individual sections. Those intermediate steps give the user something meaningful to follow, but they must also survive navigation away from the page.
Boyle reports that this workflow in a previous product took three to four minutes. Experimenting with workflows beyond five minutes would have required substantial changes to its serverless infrastructure, so the team delayed those experiments. They eventually migrated, but the work involved had already constrained product development. A runtime ceiling had become a limit on what the team was willing to try.
The application needs to stream both intermediate status and final content, then restore both after a refresh, as users expect from deep-research experiences. Recovery matters more as the work gets longer: Boyle describes an intermediate error potentially making a user repeat five minutes of work. That is a different cost from refreshing a quick webpage or resubmitting a form. Preserving progress is part of making the operation tolerable, not merely an observability feature for developers.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Infrastructure-aware components
The infrastructure built for that earlier product became the open-source GenSX library. Its central design couples the component model to the execution environment: the framework knows about the infrastructure, and the infrastructure knows about the framework. That relationship supports resumable streams for intermediate status and final output.
Boyle describes an unopinionated anti-framework inspired by React’s component model, applied to backend execution. The aim is to share and compose code without hiding the decisions that matter when building agents. Components are reusable, independently testable steps, described as idempotent; workflows collect those steps into a larger operation. Treating a step as idempotent still requires its implementation to tolerate repetition—especially if it changes an external system.
The demonstrated component uses a wrapped OpenAI SDK. The wrapper retains the familiar SDK surface and access to model parameters while adding tracing and retry tooling. The component itself remains a small function: accept a prompt and context, call the model, and return a response. It can be invoked or tested independently before becoming part of a larger workflow.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Compose the work, expose its boundaries
The demonstrated workflow fetches the Hacker News front page, analyzes its posts, generates reports, writes a tweet, and then edits the report. Ordinary TypeScript can express that sequence while leaving each operation independently replaceable and testable:
typescript
type Post = { title: string; url: string };
type Analysis = { summary: string; sources: Post[] };
type Steps = {
fetchFrontPage(): Promise<Post[]>;
analyzePosts(posts: Post[]): Promise<Analysis>;
generateReports(analysis: Analysis): Promise<string>;
writeTweet(report: string): Promise<string>;
editReport(report: string): Promise<string>;
};
async function runHackerNewsWorkflow(steps: Steps) {
const posts = await steps.fetchFrontPage();
const analysis = await steps.analyzePosts(posts);
const report = await steps.generateReports(analysis);
const tweet = await steps.writeTweet(report);
const editedReport = await steps.editReport(report);
return { report: editedReport, tweet };
}
This expresses the composition without depending on a particular version of the GenSX API. The infrastructure-aware component model adds execution behavior around the individual calls.
Each component supplies a retry boundary and an error boundary. Tracing covers both the enclosing workflow and the components nested inside it. The framework also turns workflows into REST APIs for synchronous invocation, asynchronous invocation, and retrieval of intermediate and final output streams. The same composed operation can therefore serve an immediate request or run as a background job.
The trace view exposes nested components alongside token information, OpenAI call details, and user and system messages. This makes it possible to investigate a particular model interaction within the larger workflow. For a troublesome component, the demonstrated fluent configuration API supports retries and caching, including an exponential retry policy with a configurable retry count. The policy belongs to the problematic step rather than being applied indiscriminately to the entire workflow.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Separate execution from the API connection
The deployment platform separates the API layer from the compute layer. Rather than keeping a request handler attached to a worker for the lifetime of a job, it uses a Redis Stream as the communication path:
- The API invokes compute and passes it a Redis Stream ID.
- The executing sandbox writes status and output to that stream.
- The API obtains subsequent status and output through the stream rather than continued direct communication with compute.
- The sandbox emits heartbeats that background processes monitor. If execution dies or crashes, the system can restart it or notify the user.
The browser connection no longer has to be the channel that holds the operation together.
This separation also creates independent scaling boundaries. The API can scale with client connections while compute scales with workflow execution. Boyle describes ECS as the default compute backend, with the option to bring another compute layer. Workers are stateless with respect to stored output: they communicate with the surrounding platform and write results to Redis Streams, rather than requiring the API to retrieve output from a particular worker’s memory.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Reconnect to stored progress
Both synchronous and asynchronous workflows write their output to Redis Streams. Because the API reads that stored output instead of reading directly from compute, a replacement browser connection can retrieve the history of status messages and generated content. Refreshing the page, navigating away, or terminating the browser’s connection to the API does not itself cancel the work.
For a concrete illustration, suppose the writing agent has stored Research complete at entry 1000-0 and Outline complete at 1001-0. The browser has displayed both and saved 1001-0 as its cursor. While it is disconnected, the worker adds Section 1 draft at 1002-0. On reconnect, reading after 1001-0 retrieves the missing draft; the earlier entries remain stored. Redis XREAD supports this last-seen-ID pattern. A refreshed client that has lost its local content instead needs to rebuild from retained history. Replaying output is distinct from resuming failed computation: retention and Redis persistence determine what remains available, while execution recovery and safe repetition require their own mechanisms.
Retrieve the draft produced while the browser was disconnected
Constructed example: The entry IDs, message text, saved browser cursor, and retained browser state are teaching values extending the writing-agent example. The comparison illustrates output replay, not recovery of failed computation.
Writing-agent stream; last-seen entry ID: 1001-0
Operation: Read stored entries after 1001-0, display the missing draft, and advance the browser cursor.
Redis entry 1000-0
Research complete
Research complete
Redis entry 1001-0
Outline complete
Outline complete
Redis entry 1002-0
Section 1 draft
Section 1 draft
Browser's retained research status
Research complete
Research complete
Browser's retained outline status
Outline complete
Outline complete
Browser's displayed draft
Not present
Section 1 draft
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Start small, but leave room for long-running work
There is no need to build for an hour-long workflow on day one. Start with the operation the product actually needs, while leaving room for longer execution. Coding agents and deep-research experiences motivate Boyle’s expectation that more work will become delegated: give an agent instructions, let it operate independently, and have it communicate when needed. Separating compute from the API and retaining progress in a stream allows that work to continue without requiring the user to keep a page open.
That independence also changes deployment. Safe navigation and transparent error handling are incomplete if a routine release kills active work. Boyle uses sixty-minute workflows to emphasize the need for careful worker draining and a blue-green deployment pattern. A deployment must account for workers that are still busy, not just whether replacement instances are healthy. Getting the first workflow running is easy compared with getting its lifecycle right.
Boyle closes by offering GenSX as an implementation of much of this infrastructure for developers who do not want to build it themselves. The linked repository was archived on October 2, 2025; it remains a reference for the design, rather than evidence that the hosted platform is currently available.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Resources
From the talk
TypeScript workflow framework with composable components, tracing, and agent examples. The repository was archived in October 2025.
Further reading
Instructions for creating a TypeScript workflow and integrating model SDKs.
Explains how to read stream entries after a saved ID and wait for new entries.
The 2023 announcement and examples for streaming Lambda responses through function URLs and the invocation API.
Updates since the talk
- GenSX Cloud launchArticle
Evan Boyle's subsequent launch article explains the 60-minute runtime, background invocation, storage, tracing, and durable progress streams.
Current usage-tier qualifications, request and token limits, response headers, and retry guidance.
Read the complete timestamped transcript
- 0:00
[notification sound] How agents broke infrastructure. Particularly, we're going to focus on the compute layer today. [mouse clicking]
- 0:11
My name's Evan Boyle. I'm the founder and CEO in GenSX. I was an early employee at Pulumi, and I've spent my entire career working on cloud and developer tools. [keyboard clicking]
- 0:20
Typo warning. In the spirit of embracing AI for this talk, all diagrams are AI-generated, but 4o still has some spelling issues, so thank you for your patience. We all know this journey.
- 0:31
We start off as AI engineers with a simple prompt and a couple of tool calls, and typically, this is enough to raise our ten million dollar seed round. But from there, when rubber re-meets the road, we end up building workflows, right?
- 0:43
We take that fully non-deterministic code and make as much of it deterministic as possible. That might mean chaining a couple of very specific tailored prompts together that we've written evals against, uh, and more carefully controlling the context.
- 0:57
This takes the runtime of our workflows from thirty seconds to a couple of minutes, but eventually, we all end up becoming data engineers because the most challenging part of the problem is getting the right context into the prompts.
- 1:12
And that means that we might have to crawl a user's inbox, ingest code from GitHub, or many other artifacts that require lots and lots of LLM processing.
- 1:22
But our assumptions around infra have changed. In Web 2.0, you would build a simple web service where you'd make an API request, maybe talk to a database to fetch some data, and return all that back in a few tens of milliseconds.
- 1:38
In AI applications, our P1 is a couple of seconds at best, and that's only if you're using a fast model or if you hit a prompt cache. In the previous era of infrastructure, if you had a request that took a couple of seconds, your on-call was getting paged.
- 1:54
Um, and so the infrastructure that was designed for the last ten years of the web is not really designed for the applications that we're building today.
- 2:04
LLM applications are really built on shoddy, uh, foundations. It's really hard to build reliable apps today. And if you're like us and you run a tight ship, you might have a Slack channel that looks like this, where you subscribe to, you know, issues and outages from your dependencies.
- 2:19
But luckily, this one only lasts, you know, an hour. By ten PM, it's resolved. [keyboard clicking]
- 2:24
But oh, at one twenty AM, we're back at it, and four AM, it's still going on. But surely, you know, ChatGPT and OpenAI have, have better availability, right? Well, I wouldn't really trust this ninety-nine point nine percent uptime number, and no, it's not.
- 2:40
Lots of yellow and red in this graph. But maybe we could have failed over to, you know, Gemini during this time period. Nope, we have an outage during the exact same time period.
- 2:51
And even if you don't hit an outage, you still have rate limits to contend with. A lot of these traffic patterns are gonna be extremely bursty as you batch process documents from a user or you onboard new customers, and not everybody has tier five rate limits that require spending thousands of dollars just to get to that point
- 3:09
that you can start experimenting with high levels of traffic.
- 3:14
So we start off nice and happy with our prototype. Maybe we built something on top of the Next.js chatbot template. That's easy, right? But as our workflows start running for minutes and hours, us full stack AI engineers accidentally become data engineers. [keyboard clicking]
- 3:30
So how do people solve this today? You know, there-- this used to be something that was rather niche, ro-long-running workflows, data engineering. So there is an existing set of tools.
- 3:40
People build these Rube Goldberg machines on top of queues like SQS. They might use batch processing data engineering tools like Airflow or durable execution engines like Temporal. But me personally, I'm a TypeScript developer.
- 3:52
I'm a full stack engineer, and frankly, I don't wanna use anything that was designed by a Java engineer. No offense. [keyboard clicking]
- 4:00
I'd much rather use serverless. What about existing serverless providers? They aren't really well suited for these kinds of long-running workflows. Uh, most of them time out after five minutes, and some of them even limit outgoing HTTP requests.
- 4:14
And for all of them, they don't really have native streaming support. Streaming is something that you have to bolt on at the application layer and not something that's a native part of the infrastructure that you're building on top of.
- 4:27
Something that's really important when you're building an application that might run for multiple minutes, users might refresh the page, so you want resumability.
- 4:35
And so let's look at some of these common product experiences. We're gonna look at both onboarding, where we might ingest a bunch of data from the user with an LLM up front, and then also a product experience where we're gonna run an agent that's gonna take multiple minutes, and we have to keep the user engaged during that
- 4:51
time period. So during this onboarding experience, the user puts in their URL, right? And we use a single LLM call to grab some information from that web page and then detect all the pages that we're gonna scrape, right?
- 5:04
And now we've kicked off that scraping job in the background, and it's gonna take multiple minutes. Uh, and we're gonna be making hundreds of LLM calls to extract content from those web pages and enrich them.
- 5:14
And we want the user to be able to start using the product right away. So this ingestion can take, you know, a varying amount of time, but we want users to use the app immediately.
- 5:25
If we wait ten minutes, that means we're gonna have increased fall off in the funnel, so we have to run this in the background, right? And we wanna show users the status of this ingestion as they're using the product.
- 5:35
We want them to know, "Hey, as time goes on, we're gonna enrich more data, and your experience is gonna get better." [keyboard clicking]
- 5:42
Next, this is an example of building a content generation app, right? We're gonna write a blog post, uh, about building high-performance web apps with Vercel and Next.js. And this agent, we tell the user up front, "Sit back and relax.
- 5:56
This is gonna take a couple of minutes." And on the right, we're showing them all of the different steps, right? We're running research. We're writing an outline. And we're writing each section step by step.
- 6:07
Since this takes multiple minutes, it's really important that if the user leaves the page or navigates away, that they don't lose this context, right?
- 6:16
And so that workflow that we built when working on a previous product took three to four minutes, and we really felt a lot of friction experimenting with longer workflows.
- 6:26
Like, we were deterred from making our workflows longer than five-plus minutes because that meant that we would have to make deep infra changes due to limitations from our serverless provider.
- 6:37
Eventually, we did rip it out, and it was a bunch of work, but it took us much longer than we should have to run those experiments, uh, because of the amount of work that was required to m-migrate off of, you know, our easy-to-use serverless offering.
- 6:52
Also, we need to stream both the final content as well as the intermediate status, and if the user refreshes the page and comes back, we want them to see that same thing, just like you get with deep research, right?
- 7:04
And if there's an intermediate error, users are gonna be way more frustrated if it takes them five minutes to get back to that same point, uh, versus if it's just, you know, a simple webpage that you have to refresh or a form that you have to resubmit.
- 7:18
So we built a lot to make this easy in our core product, uh, when we were working on, you know, agentic workflows, uh, and we ended up turning a lot of this into an open source library.
- 7:30
So we built a simple component model that's infra-infrastructure aware, right? Uh, the, the framework itself is very aware of the infrastructure it's running on, and the infrastructure is aware of the framework.
- 7:42
And that's so that we can provide things like resumable streams for intermediate status, uh, and final output, and we call this a bit of an anti-framework. It's unopinionated and focused on building blocks.
- 7:54
Uh, it's-- it takes inspiration from React's component model and applies it to the back end 'cause we know that abstraction is bad when building agents. You don't want to abstract.
- 8:03
You want to share. You want to compose. You want to reuse code. So we have components that are reusable, idempotent, independently testable steps, and then workflows that are collections of components that run together.
- 8:16
So this is a simple component that uses a wrapped version of the OpenAI SDK. It's wrapped so that we can get a bunch of other tooling for retries and tracing and things like that, but it's sa- the same exact OpenAI surface area that you would expect.
- 8:29
We give you full access to the model, so it's just a prompt, a little bit of context that's injects-ingested, and it returns a response. So a simple function that takes in some prompts and returns some output, and it can be independently run or tested.
- 8:43
We can also combine it together into what we call a workflow. This workflow fetches the front page of Hacker News, analyzes those posts, generates reports, writes a tweet, and then edits the report.
- 8:55
And with this, every single step, we're gonna get a retry boundary, an error boundary off each component, and we're gonna get traces, both at the top level of the workflow, but also all of the components that run within it.
- 9:09
Each workflow can be turned into a set of REST APIs automatically by the framework that support synchronous invocation as well as asynchronous invocation and the relevant API so that we can retrieve the intermediate stream and the final output stream if needed.
- 9:27
When we run this workflow, we see that we get a trace. This trace shows us all of the nested components that run inside the workflow, including all the tokens, all the details on the OpenAI call, user messages, system messages, so it makes it super easy to debug.
- 9:42
And we have built-in retries. Every component has a fluent API hung off of it that allows you to configure a component with things like retries and a cache. So if I have one component that's particularly problematic, I can add an exponential retry policy, uh, with...
- 9:57
and, and configure the number of retries that run.
- 10:01
And so this all gets deployed to a serverless platform that we built that's tailor-made for long-running workflows and building agentic UIs, uh, for processes that run in the background.
- 10:14
So we have an API layer and a compute layer that are completely separate, and this is really important for a lot of reasons. The API, the API layer invokes the compute layer and passes it in a Redis Stream ID.
- 10:27
That's the last time that the API layer is gonna have to talk to the compute layer. The rest of it is going to happen via communication with this Redis Stream.
- 10:34
Status is gonna come from the Redis Stream. The output is gonna come from the Redis Stream. And as the sandbox program executes, it's gonna emit heartbeats so that the background processes within the system can monitor and make sure that a workflow runs to completion and doesn't die or doesn't crash.
- 10:51
And if it does, we can automatically restart it or notify a user.
- 10:57
So key architectural points of this is this separation between the API and the compute layer. It allows us to scale things independently, scale the API layer independent of the compute layer.
- 11:07
It also allows us to plug that compute layer, so we can provide, uh, a compute layer by default on top of ECS, but we can allow users to bring their own compute layer as well since it's completely stateless and just talks to the API layer and the Redis Streams to store output.
- 11:23
All that API goes to the Redis Stream, both for sync and async workflows, which means that we get resumability, right? The API layer only reads from the Redis Stream, not the compute layer directly, so that means that we can build UIs that allow users to refresh the page, navigate away, transparently handle errors, uh, and they still get
- 11:41
the full history of status messages and all of the output, um, something that you wouldn't get from a typical serverless like infra platform.
- 11:52
Like we said, key point here is being able to refresh the page, resume directly from the Redis Stream, and get all of your intermediate status messages. None of the work is lost if the new user navigates away or if the web browser terminates the connection to the API server.
- 12:07
So things and lessons to consider when you're building your own infrastructure for agentic workflows. Always start simple. You're not gonna write a workflow that runs for an hour on day one, so don't build for it.
- 12:19
But do plan for a future that's long-running. In my opinion, this is where agents are going, and I think that we can see this with all of the recent coding agents that have come around, experiences like deep research.
- 12:30
Like, the future is giving your agent instructions and letting it go off and do work for you and communicate with you when you need it. And to make that happen, think about keeping your compute and API plane separate and lean on Redis Streams for resumability.
- 12:45
Make it easy to u- for users to navigate away from the page, not lose progress, and handle errors transparently. All this is also to say you gotta take care when deploying.
- 12:55
If you're gonna let your workflows run for sixty minutes, you have to be very, very careful about how you drain workers and how you, uh, do kind of a blue-green deployment pattern.
- 13:04
And overall, the devil is really in the details. Easy to get started, but very hard to get this right.
- 13:11
Now, it's really, really fun to build all of this infrastructure yourself. But if you don't wanna build it yourself, I'd encourage you to check out GenSX on GitHub, where we've implemented a lot of this for you.
- 13:23
Again, my name's Evan. Thanks for having me at this talk, uh, and happy building.