UI Decision Layer

The UI Decision Layer is the core of Fidus's AI-Driven UI. It analyzes user context and dynamically decides which UI form to render—then actually renders it.

⚠️ Note: This demo uses a mock decision service with heuristics. In production, the UIDecisionLayer calls an LLM (GPT-4, Claude, etc.) to make context-aware decisions. The architecture and component rendering work exactly as in production.

Why This Matters: Real Examples

1. Expert vs Beginner

Query: "Create a budget"

  • Expert (9/10): → Form (fast, no handholding)
  • Beginner (2/10): → Wizard (guided, explained)

2. Time-Sensitive vs Planning

Query: "My schedule"

  • Morning (7 AM): → Today's widget (urgent)
  • Sunday: → Week calendar (planning)

3. Context from History

Query: "Show budget"

  • Recently overspent: → Alert + advice
  • On track: → Simple widget
  • First time: → Tutorial + setup wizard

4. No Fixed Navigation

Traditional app: Finance tab → Always same screen

  • Urgent: Budget alert card
  • Normal: Spending trends
  • Empty state: Setup prompt

How It Works

Decision → Registry → Render

1
Collect Context: User query, time, location, expertise, device type, user history
2
LLM Decision: Analyze context → Choose UI form (chat/form/widget/wizard) + component type
3
Registry Lookup: Resolve component from Component Registry
4
Dynamic Render: Render component with generated props

Interactive Demo

Enter a query and adjust context to see how the UI Decision Layer chooses AND RENDERS the appropriate UI component.

☀️ Daytime
📈 Intermediate

Key Principles

  • Context-Adaptive: Same query → Different UI based on situation
  • Dynamic Rendering: Components rendered at runtime, not hardcoded routes
  • Component Registry: Centralized mapping of component types to React components
  • Props Generation: LLM generates appropriate props (pre-filled forms, data)
  • Explainable: Every decision includes reasoning
  • User-Optimized: Expertise level influences UI complexity

Real-World Examples

Same Intent, Different Context = Different UI

The power of AI-Driven UI is that the same user intent produces different interfaces based on context:

Scenario 1: "I need to budget for groceries"

Context: Morning (8 AM), Expert user (9/10), on desktop
Decision: Direct Form with pre-filled category "Food"
Why: Expert users in the morning want speed. Skip explanations, show fields.

Scenario 2: "I need to budget for groceries"

Context: Evening (8 PM), Beginner (2/10), on mobile
Decision: Conversational Wizard
Why: Beginner needs guidance. Evening = less time pressure. Mobile = step-by-step better.

Scenario 3: "I need to budget for groceries"

Context: Afternoon (2 PM), Intermediate (5/10), just overspent last month
Decision: Chat with suggestions based on history
Why: User history suggests they struggle with budgets. Offer personalized advice first.

Context-Aware Proactivity

The UI Decision Layer doesn't just react—it adapts proactively:

  • Morning commute (7:30 AM): "My schedule" → Shows today's appointments as widget (time-sensitive)
  • Planning session (Sunday afternoon): "My schedule" → Shows calendar view (week overview)
  • After meeting invite: "My schedule" → Shows conflict checker form (action-oriented)

No Fixed Screens, Only Opportunities

Traditional UI: User clicks "Finance" → Always sees the same dashboard
AI-Driven UI: User opens Fidus → LLM decides what's relevant NOW:
  • • Budget overage? → Show alert card
  • • Upcoming bill? → Show payment reminder
  • • Nothing urgent? → Show spending trends
The dashboard is an Opportunity Surface, not a fixed layout.

Implementation in Production

// Backend: UI Decision Layer Service
class UIDecisionLayerService {
  async decide(context: UserContext): Promise<UIDecision> {
    // Call LLM with context
    const llmResponse = await this.llm.chat({
      messages: [
        {
          role: 'system',
          content: 'You are a UI decision engine. Analyze context and decide optimal UI form.'
        },
        {
          role: 'user',
          content: JSON.stringify(context)
        }
      ]
    });

    // Parse LLM response
    return {
      uiForm: llmResponse.uiForm,
      componentType: llmResponse.componentType,
      props: llmResponse.props,
      confidence: llmResponse.confidence,
      explanation: llmResponse.reasoning
    };
  }
}

// Frontend: Dynamic Rendering
function DynamicUI({ decision }: { decision: UIDecision }) {
  const Component = ComponentRegistry.get(decision.componentType);

  if (!Component) {
    console.error(`Component ${decision.componentType} not found`);
    return <ErrorFallback />;
  }

  return <Component {...decision.props} />;
}

Related Documentation