Contact Andrii

AI Agent UI Widgets - Why I Chose a Custom Implementation Over CopilotKit, AI SDK, LangChain, and Google A2UI

Cover Image for AI Agent UI Widgets - Why I Chose a Custom Implementation Over CopilotKit, AI SDK, LangChain, and Google A2UI
Andrii Kycha
Andrii Kycha

AI Agent UI Widgets in 2026 - Why I Chose a Custom Implementation Over CopilotKit, AI SDK, LangChain

If you are building AI agents today, you will eventually hit this problem:

Plain text responses are not enough.

You need UI.

Not just markdown. Not just chat bubbles.

You need:

  • User cards
  • Lists
  • Action panels
  • Structured outputs that feel like a real product

This article breaks down:

  • The actual problem behind AI UI widgets
  • The popular solutions (CopilotKit, AI SDK, LangChain, Google A2UI)
  • Why I rejected all of them
  • The custom architecture I ended up shipping in production

The Real Problem - AI Needs UI, Not Just Text

Most teams start with this:

User -> Prompt -> LLM -> Text response

Looks fine in demos. Falls apart in real products.

Example

Instead of:

"Here are your leads: John, Sarah, Mike"

You actually need:

  • A list of leads
  • Each with actions (message, call, view profile)
  • Possibly enriched with metadata

So the real requirement becomes:

Render structured UI components driven by the LLM

This is not a chat problem anymore. This is a UI rendering problem with AI as the input layer.

Comparing LLM Outputs

The Goal

Let the AI agent decide what to render, not just what to say

That means:

  • AI outputs structured data
  • UI renders components dynamically
  • System stays stable and predictable

Options I Evaluated

I looked at:

  • CopilotKit
  • Vercel AI SDK
  • LangChain
  • Google A2UI

The main issue behind all of them was the same:

  • I wanted to avoid early vendor lock-in while there is still no clear major player in this space
  • The abstractions for AI-driven UI are still changing and may look very different over time
  • There are still not enough companies using these SDKs in production
  • There is a lack of strong case studies showing long-term success with these approaches
  • Reviewing open source implementations based on structured outputs and tool calling felt more valuable than committing early to a specific SDK

The Core Problem With All SDKs

Every solution introduces some level of:

  • Lock-in
  • Hidden abstraction
  • Assumptions about how UI should work

And here is the reality:

We do not yet know what the "correct" abstraction for AI UI is

This space is still forming.

Choosing an SDK today is a bet on:

  • Vendor direction
  • API stability
  • Community adoption

That is a risky bet in 2026.

Why I Chose Custom Implementation

I optimized for:

  • Flexibility
  • Long-term stability
  • Control over UX
  • Ability to evolve with the ecosystem

Instead of:

  • Convenience
  • Prebuilt abstractions

The Architecture I Built

Solution High-Level Architecture

1. Tool Calling Defines UI

The agent does not return UI directly.

It returns structured tool output:

{
  "type": "user_list",
  "users": [
    { "id": 1, "name": "John Doe" },
    { "id": 2, "name": "Sarah Smith" }
  ]
}

This is generated via tool calling.

2. Content Blocks

Every AI response is normalized into:

type ContentBlock =
  | { type: "text"; content: string }
  | { type: "component"; component: ComponentDefinition };

3. UI Switch Renderer

On the frontend:

switch (block.type) {
  case "text":
    return <ChatMessage text={block.content} />;
  case "component":
    return renderComponent(block.component);
}

4. Component Registry

const registry = {
  user_list: UserList,
  user_card: UserCard,
};

5. Strict Schemas (Critical)

I enforce schemas using tools (Pydantic / Zod).

Why?

Because:

If the AI output is not predictable, your UI will break

Why This Approach Works

1. Zero Vendor Lock-In

I do not have to build my infrastructure and architecture around a vendor that may lower the priority of maintaining the solution later.

That risk matters even more in this space because many of these products still do not have enough real production users.

If the vendor changes direction in a way that is far from actual market expectations, I am not forced to rewrite core parts of my system around their roadmap.

2. Stable Contracts

The contract is explicit:

AI -> JSON -> UI

Not:

AI SDK -> Magic -> UI

I know exactly how the solution works because there is no hidden layer translating things behind the scenes.

That makes the system easier to reason about, debug, and evolve.

It also gives me the flexibility to add the functionality my business logic actually requires without hitting the limits of a faulty abstraction.

That matters a lot while the UI widgets concept is still very early and the "right" abstraction is not settled yet.

Custom Implementation vs. Hidden Abstraction

3. Production Reliability

SDKs evolve fast.

That means:

  • Breaking changes
  • Deprecated APIs
  • Rewrites

With custom:

I control the surface area

4. Easier Debugging

When something breaks:

  • I inspect JSON
  • I inspect schema validation

No black boxes.

5. Future-Proofing

This space will change.

A lot.

Likely outcomes:

  • New standards emerge
  • Current SDKs pivot or die
  • UI patterns evolve rapidly

Custom approach lets me adapt.

What About Speed of Development?

For a new project, this is usually slower upfront.

But that was not my situation.

I was adding this to an existing project that already had its transport layer built around WebSockets.

Most SDKs in this space assume SSE as the default transport.

That means adopting them would not actually save me time. I would still need to adapt my architecture around their assumptions or build compatibility layers on top of what I already had.

So in my case, the custom implementation was not only better for architecture, it was also faster.

It fit the system that already existed instead of forcing me to reshape working infrastructure just to match an SDK.

For a serious product, this trade-off is worth it.

App Using Websocket Transport Layer Diagram

What I Learned Building This

Tool calling is enough

You do not need a full framework.

You need:

  • Good schemas
  • Good validation
  • Clean rendering layer

When You Should NOT Do This

Use SDKs if:

  • You are prototyping
  • You are validating an idea
  • You do not need long-term flexibility

Final Take

AI UI widgets are still an unsolved problem.

Right now:

  • No dominant framework
  • No stable abstraction
  • No proven best practice

So my strategy is simple:

Do not lock in early.

Build:

  • Simple
  • Transparent
  • Replaceable systems

Let the ecosystem mature before committing.

If You Are Building AI UI Today

Start here:

  • Use tool calling
  • Define strict schemas
  • Render UI via component registry
  • Keep your system modular

Everything else is optional.

Summary

Building AI UI widgets with a custom implementation gave me the control I needed at a stage where the space is still immature and the abstractions are not stable yet.

Instead of optimizing for short-term SDK convenience, I optimized for:

  • Zero vendor lock-in
  • Stable and explicit contracts
  • Flexibility for business-specific logic
  • Reliability in production
  • Faster integration with my existing WebSocket-based architecture

For me, that tradeoff was worth it.

If the ecosystem matures and stronger standards emerge, I can adapt later without having to unwind a framework-shaped foundation.

If you liked this article, you might also enjoy my previous AI-related post:
Case Study: Secure Authentication for AI Agents Running Scheduled Tasks

Until next time and happy coding! 🧑‍💻