GenUI-LoomAgent

March 10, 2026 · View on GitHub

LOOM Logo

GenUI-LoomAgent

AI decides what to show, not just what to say.

An open-source Generative UI Agent framework — the AI doesn't just return text, it autonomously decides which UI components to render.

Plug in any REST API via YAML config. No backend code changes needed.

AG-UI Compatible License: Apache 2.0 Python Next.js

English · 中文

GenUI-LoomAgent Demo

Quick Start · Architecture · AG-UI Protocol · Add Services · Contributing


What is LOOM?

LOOM is a Generative UI (GenUI) Agent framework. Traditional AI apps return plain text. LOOM's AI backend generates text responses and autonomously decides which UI components to render — data lists, comparison tables, charts, weather cards, trip cards, and more — all orchestrated by the AI in real time.

User: "What's the weather like in Beijing tomorrow?"

Traditional AI  →  A paragraph describing the weather
LOOM AI         →  Short summary + WeatherCard (temp/humidity/wind) + Graph (7-day trend)

User: "Find me a train from Beijing to Shanghai"

Traditional AI  →  A paragraph listing trains
LOOM AI         →  Brief summary + TripCard (train/time/price) + DataList (available options)

Core Features

FeatureDescription
GenUI Dynamic RenderingAI returns { name, props } instructions, frontend dynamically renders registered components
Declarative Service IntegrationAdd any REST API via YAML config — 5 lines to connect a new data source
Multi-Intent Parallel ProcessingSingle message with multiple needs → automatic task decomposition and parallel execution
Emotional Memory SystemTime-aware context + behavioral signals + user memory extraction — AI remembers your preferences
Narrative FlowNot just "text + card" stitching, but story-driven information delivery with mood and rhythm
Streaming SSEReal-time streaming responses with interrupt and retry support
AG-UI ProtocolCompatible with AG-UI standard protocol, works with CopilotKit and other AG-UI clients
Mobile ReadyCapacitor for iOS packaging, mobile-first UI design

Tech Stack

LayerTechnologies
FrontendNext.js 15 · React 19 · TypeScript · Tailwind CSS v4
BackendPython · FastAPI · LangGraph
LLM GatewayLiteLLM — unified interface for any LLM provider
ProtocolAG-UI (Agent-User Interaction Protocol)
DatabaseMongoDB
MobileCapacitor (iOS)
TestingVitest · React Testing Library · Pytest

Supported LLM Providers

Powered by LiteLLM, LOOM works with any LLM provider out of the box. Just set LLM_MODEL and LLM_API_KEY in your .env:

ProviderExample LLM_MODELNotes
OpenRouteropenrouter/google/gemini-2.5-proAccess 200+ models through one API key
OpenAIopenai/gpt-4o
Anthropicanthropic/claude-sonnet-4-20250514
Googlegemini/gemini-2.5-pro
DashScope (Qwen)dashscope/qwen3.5-plusRecommended for Chinese users
DeepSeekdeepseek/deepseek-chat
Any OpenAI-compatibleSet LLM_BASE_URLWorks with any provider that supports the OpenAI API format

You can also set LLM_FAST_MODEL separately for lightweight tasks (intent recognition, memory extraction) to reduce cost.

Search Services

LOOM supports web search via YAML-configured REST APIs:

ServiceBest ForEnv Var
Zhipu AI Web SearchChinese content — better results for Chinese queriesZHIPU_API_KEY
TavilyInternational content — deep search with extracted contentTAVILY_API_KEY

Both can be enabled simultaneously — the AI will choose the most appropriate one based on the query language and context.


🚀 Quick Start

git clone https://github.com/qingkongzhiqian/GenUI-LoomAgent.git
cd GenUI-LoomAgent

cp backend/.env.example backend/.env
# Edit backend/.env — fill in your LLM API key

docker compose up

Open http://localhost:3000 — frontend, backend, and MongoDB are all running.

Option B: Manual Setup

Prerequisites

  • Node.js 20+
  • Python 3.10+
  • MongoDB (local or cloud)

1. Frontend

cd frontend
npm install
cp example.env.local .env.local
npm run dev

Open http://localhost:3000

2. Backend

cd backend
pip install -r requirements.txt
cp .env.example .env
# Edit .env — fill in your LLM API key (DashScope or OpenAI)

python run.py

Backend runs at http://localhost:8000

Configuration

Frontend (frontend/.env.local):

VariableDescription
BACKEND_URLBackend address for SSR proxy
NEXT_PUBLIC_BACKEND_URLClient-side direct URL (for Capacitor)

Backend (backend/.env):

VariableDescription
LLM_MODELModel identifier (e.g. openrouter/google/gemini-2.5-pro, dashscope/qwen3.5-plus)
LLM_API_KEYAPI key for your LLM provider
LLM_BASE_URLCustom endpoint (optional, for OpenAI-compatible providers)
LLM_FAST_MODELLightweight model for fast tasks (optional, defaults to LLM_MODEL)
MONGODB_URIMongoDB connection string
JWT_SECRETJWT signing key
TAVILY_API_KEYTavily search API key (optional)
ZHIPU_API_KEYZhipu AI search API key (optional)

Generate a JWT secret: python -c "import secrets; print(secrets.token_urlsafe(32))"

Deploy

Frontend → Vercel (one click):

Deploy with Vercel

Set BACKEND_URL to your backend's public URL. Set Root Directory to frontend.

Backend → Any Python host (Railway, Render, fly.io, etc.):

cd backend
pip install -r requirements.txt
python run.py

LangGraph Nodes

NodeResponsibility
InitializerLoads chat history, user memory, environmental context, and emotional context in parallel
PlannerIntent recognition and task decomposition — splits complex requests into dependency-ordered execution plans
ExecutorRuns plan steps — independent steps execute in parallel, dependent steps wait for prerequisites
EvaluatorConditional routing — if steps remain, loop back to Executor; otherwise proceed to Synthesizer (max 5 iterations)
SynthesizerGenerates final text response + GenUI component instructions; emits AG-UI events

Data Flow

User Input
  → Initializer (load history, memory, emotional context)
  → Planner (intent recognition + task decomposition)
  → Executor (parallel sub-task execution)
    ├─ Chat intent → mark as complete
    └─ Service intent → REST API call via adapter
  → Evaluator (check completion, loop or proceed)
  → Synthesizer (refine results → generate text + components)
  → AG-UI Event Stream → Frontend
    ├─ TEXT_MESSAGE_CHUNK  (streaming text)
    ├─ TOOL_CALL_START / ARGS / END / RESULT  (service calls)
    ├─ CUSTOM genui:components  ({ name, props })
    ├─ CUSTOM genui:narrative  (mood, opener, insight, next_actions)
    └─ CUSTOM genui:sources  (reference links)
  → Component Registry → Dynamic UI Rendering

GenUI Components

The AI can dynamically render any of these registered components:

ComponentUse Case
DataListLists, bullet points, resource collections
DetailPanelKnowledge cards, entity details
DataTableComparisons, rankings, parameter tables
GraphBar / Line / Pie charts
TripCardTravel and transportation info
WeatherCardWeather forecasts
MetricCardKPIs and numeric indicators
StepCardStep-by-step processes
QuoteCardQuotes, definitions, facts
POIListPoints of interest
LinkPreviewURL previews
ClarifyCardClarification questions

🔌 AG-UI Protocol

GenUI-LoomAgent is compatible with AG-UI (Agent-User Interaction Protocol) — an open standard that defines how AI agents interact with frontend applications in real time.

Why AG-UI?

AG-UI complements MCP and A2A to form a complete Agent protocol stack:

ProtocolRole
MCPGives agents access to tools
A2AAgent-to-agent communication
AG-UIAgent-to-user interface (this project)

Event Stream

The backend sends standard AG-UI events via SSE:

RUN_STARTED → STEP_STARTED → ACTIVITY_SNAPSHOT (execution plan)
→ TOOL_CALL_START → TOOL_CALL_ARGS → TOOL_CALL_END → TOOL_CALL_RESULT
→ TEXT_MESSAGE_CHUNK → CUSTOM("genui:components")
→ CUSTOM("genui:narrative") → RUN_FINISHED

GenUI Extension Events

On top of AG-UI standard events, this project uses CUSTOM events for GenUI-specific capabilities:

Event NamePurpose
genui:componentsAI-generated UI component list ([{ name, props }])
genui:narrativeNarrative flow data (mood, insight, suggested actions)
genui:clarifyClarification questions when user intent is ambiguous
genui:sourcesReference links and data sources

Third-Party Integration

Any AG-UI compatible frontend client (e.g. CopilotKit, @ag-ui/client) can connect directly to the backend:

import { HttpAgent } from "@ag-ui/client";

const agent = new HttpAgent({
  url: "http://localhost:8000/api/chat/stream",
});

const result = await agent.runAgent({
  messages: [{ id: "1", role: "user", content: "What's the weather in Beijing?" }],
});

🔧 Add Services

Services are configured declaratively in backend/services.yaml — no backend code changes required.

REST API Example

services:
  - id: "my-search"
    type: "rest"
    name: "My Search API"
    description: "Search products from my backend"
    endpoint: "https://api.example.com/search"
    method: "POST"
    headers:
      Authorization: "Bearer ${MY_API_KEY}"
    parameters_schema:
      type: "object"
      properties:
        query:
          type: "string"
          description: "Search keyword"
      required: ["query"]
    ui_hint:
      component: "ProductList"
      formatter: "format_products"

Configuration Fields

FieldDescription
idUnique service identifier
descriptionThe AI reads this to decide when to invoke the service — be specific
parameters_schemaJSON Schema format — the AI extracts parameters from user input based on this
requires_envOptional — service only enabled when all listed env vars exist
payload_defaultsOptional — default fields included in every request
timeoutOptional — request timeout in seconds

See services.example.yaml for more examples.


📁 Project Structure

GenUI-LoomAgent/
├── frontend/                       # Next.js frontend
│   └── src/
│       ├── app/chat/               # Chat page
│       ├── components/
│       │   ├── custom-chat/        # Component registry & renderer
│       │   ├── charts/             # Chart components (Recharts)
│       │   └── primitives/         # GenUI components (DataList, TripCard, etc.)
│       ├── hooks/                  # useCustomChat and other hooks
│       ├── contexts/               # Auth, language contexts
│       ├── i18n/                   # Internationalization (zh/en)
│       ├── lib/                    # API client, utilities
│       └── types/                  # Shared TypeScript types

├── backend/                        # FastAPI + LangGraph backend
│   └── app/
│       ├── agent/
│       │   ├── nodes/              # LangGraph nodes (initializer → planner → executor → evaluator → synthesizer)
│       │   ├── services/           # Service registry, REST adapter
│       │   ├── memory/             # User memory extraction & storage
│       │   ├── emotional/          # Emotional context builder
│       │   └── prompts/            # LLM prompt templates
│       ├── auth/                   # JWT authentication
│       ├── crud/                   # MongoDB operations
│       └── models/                 # Data models

├── .github/                        # CI/CD, issue templates, assets
├── docker-compose.yml              # One-command full-stack startup
├── CONTRIBUTING.md
├── CHANGELOG.md
└── LICENSE                         # Apache 2.0

📜 Available Scripts

# Frontend (from frontend/)
npm run dev              # Dev server
npm run build            # Production build
npm run start            # Production server
npm run lint             # ESLint
npm run typecheck        # TypeScript type check
npm test                 # Vitest
npm run analyze          # Bundle size analysis

# Backend (from backend/)
python run.py            # Start server

🤝 Contributing

Contributions welcome! See CONTRIBUTING.md for guidelines on:

  • Adding new GenUI components
  • Adding new REST API services
  • Improving the Agent workflow

📄 License

Apache 2.0