Dev.to WebDev 🛠 Dev 👁 0 📖 5 min read

Three Questions to Answer Before You Ship an Agent UI

Most teams building an agent UI start with the chat box and work backwards. I think that is the wrong order. The decisions that shape the product are made earlier, usually by default, and usually without anyone noticin

Most teams building an agent UI start with the chat box and work backwards.

I think that is the wrong order.

The decisions that shape the product are made earlier, usually by default, and usually without anyone noticing they were decisions.

In this post, I want to give the three I keep coming back to:

  1. Where does the agent loop run?
  2. How does the model hand you UI?
  3. Which dimension did your tests delete?

I build in Angular and I maintain Threadplane, so my examples lean that way. The questions apply to any framework.

tl;dr

  • The agent loop runs in one of three places: a vendor's server, your route running a vendor's code, or your agent. Pick on purpose.
  • Generative UI is not one thing. The useful choice is between a fixed spec you validate up front and a live surface the agent keeps editing.
  • Every deterministic test harness buys determinism by deleting a dimension of the real system. Know which one yours deleted.

1. Where does the agent loop run?

The agent loop is the code that calls the model, sees a tool call, runs it, and calls the model again.

Where it lives decides who holds the API key, where approvals pause, where threads persist, and whose release schedule you are on.

I compared five libraries on this in September 2026. The answers sort into three shapes:

  • A vendor server in the request path. You deploy the library's runtime and your browser talks to it. You get key custody, auth, routing, and trusted middleware in one place. You trade a second server on the hot path.
  • Vendor code in your route. No box to deploy, but the loop is the library's, inside an API route you own. Approvals and persistence can be first-class because the library owns both ends. You trade a loop that is separate from the one your agent framework already has.
  • Your agent. The UI talks to the agent server directly. One loop, owned by the framework you already chose. You trade the ability to show anything the server does not send.

For me, the third shape is right for most teams, and it is the one Threadplane is built on.

If you are running an agent, you already have a server. It holds the model key, it already authenticates, and it already sees every tool call. A vendor's box in front of it is a second place to solve a problem you already had one place to solve.

That does not mean no server at all. Put an endpoint you own in front of your agent for auth and credentials. The difference from a vendor runtime is who owns the code running in it.

The full comparison, with every cell source-checked and the costs of my own choice listed, is in Why Do Agent UI Libraries Require a Runtime?

2. How does the model hand you UI?

"Generative UI" hides three mechanisms behind one phrase:

  • Tool-call rendering. The model calls a tool and you map the tool name to a component. Every library does this, and it is where most teams should start.
  • Declarative specs. The model authors a UI tree in a standard format and the client renders it from a catalog you registered. The two open specs gaining ground are A2UI and json-render.
  • Sandboxed apps. An MCP server returns a ui:// resource and the client mounts it in an iframe. This is MCP Apps, and my project does not render it yet.

The choice that matters is inside the second bucket, and it is about contract shape.

With a fixed spec like json-render, the contract is application-owned. You define the schema, validate the whole spec before it mounts, and your handlers decide what a click means.

With a live protocol like A2UI, the surface is agent-owned. The agent creates it, keeps editing it across turns, and receives structured actions back.

My heuristic is simple. If you can validate the entire UI before it renders, start with the fixed spec. If the surface has to live past its first render, step up to the protocol.

An order summary card is a fixed spec. A three-day itinerary that fills in prices and gets rewritten when the user objects is a live surface.

The walkthrough with the same card in both formats is in json-render vs A2UI.

3. Which dimension did your tests delete?

Agents are hard to test end to end because the model does not return the same thing twice.

The usual fix is to record its responses as fixtures and replay them. We test our whole demo fleet that way, and I recommend it. Two things about that setup deserve more thought than they get:

  • Where you put the mock decides what is under test. Mock at the app boundary and you have proven your component renders what you handed it. Mock at the model provider, with the real agent server running against a fake model endpoint, and your routing, streaming, and tool round-trips are all under test.
  • Every deterministic harness deletes a dimension. Ours deletes time. Replayed responses arrive in one or two chunks instead of token by token, so final-DOM assertions stay stable. A handful of fixtures opt back in with tiny chunks where the progressive render is the thing under test.

Here is the bug class that disappears when you delete time. A child agent streams tokens, a client merges them into the transcript as an extra bubble, and then the run settles and the transcript is rebuilt correctly. Assert on the finished DOM and the test passes. Any assertion after an await sees a settled system, and a self-correcting bug is one that settles.

So the question about your harness is not whether it is green. It is which dimension you deleted, and which tests opted back in.

The full accounting is in What Fixture Replay Can't Catch.

Conclusion

Each of these questions has a default answer that arrives with whatever library you install first. None of the defaults is wrong, but all of them are decisions, and I think you should make them as decisions.

For me: run the loop in the agent with an endpoint you own in front of it, start with a fixed UI spec and step up per surface, and mock at the model provider while knowing what you gave up.

Those are the answers Threadplane is built around. If you are building the same thing in another framework, I would like to hear where yours landed.

📰 Read the original article on Dev.to WebDev

Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.