Multi-modal Agents with UI-TARS

UI-TARSMultimodalAutomationTutorial

Build desktop automation agents that can see, understand, and interact with UI elements.

Multi-modal Agents with UI-TARS

Overview

UI-TARS (User Interface - Task Automation and Reasoning System) is ByteDance's open-source multimodal AI agent stack for desktop UI automation. This tutorial shows you how to build agents that can see, understand, and interact with desktop applications.

Prerequisites

  • Python 3.10+
  • UI-TARS model access (via API or local deployment)
  • Desktop OS (Windows, macOS, or Linux)
  • ~16GB RAM for local inference

Installation

# Install UI-TARS
pip install ui-tars

# Or with all dependencies
pip install ui-tars[desktop,vision]

# For local model (requires API access)
pip install ui-tars[local]

Architecture Overview

┌─────────────────────────────────────────────────────────────┐
│                      UI-TARS Agent                          │
├─────────────────────────────────────────────────────────────┤
│  ┌──────────┐    ┌──────────┐    ┌──────────┐             │
│  │  Vision  │───▶│ Planning │───▶│ Action   │             │
│  │ Encoder  │    │  Engine  │    │ Executor │             │
│  └──────────┘    └──────────┘    └──────────┘             │
│       │               │               │                    │
│       ▼               ▼               ▼                    │
│  ┌──────────┐    ┌──────────┐    ┌──────────┐             │
│  │  Screen  │    │  Task    │    │  UI      │             │
│  │ Capture  │    │  Queue   │    │ Control  │             │
│  └──────────┘    └──────────┘    └──────────┘             │
└─────────────────────────────────────────────────────────────┘

Step 1: Basic Setup

Configuration

# config.py
from ui_tars import UIAgent

# Initialize agent
agent = UIAgent(
    model="ui-tars-desktop",
    vision_encoder="clip-vit-large",
    action_space="desktop"
)

Screen Capture

# src/capture.py
from ui_tars.vision import ScreenCapture

capture = ScreenCapture()

# Capture current screen
screenshot = capture.capture()

# Capture specific region
region_screenshot = capture.capture_region(x=100, y=100, width=500, height=300)

# Continuous capture for real-time interaction
for frame in capture.stream():
    process_frame(frame)

Step 2: Visual Understanding

Element Detection

# src/detection.py
from ui_tars.vision import ElementDetector

detector = ElementDetector()

# Detect all interactive elements
elements = detector.detect_elements(screenshot)

for element in elements:
    print(f"Element: {element.type}")
    print(f"  Position: {element.bbox}")
    print(f"  Text: {element.text}")
    print(f"  Confidence: {element.confidence}")

UI Hierarchy Parsing

# src/hierarchy.py
from ui_tars.vision import UIHierarchyParser

parser = UIHierarchyParser()

# Parse UI hierarchy
hierarchy = parser.parse(screenshot)

# Navigate hierarchy
def find_button(hierarchy, text: str):
    for element in hierarchy.iter_elements():
        if element.type == "button" and text.lower() in element.text.lower():
            return element
    return None

button = find_button(hierarchy, "Submit")

Step 3: Task Planning

Goal-Oriented Planning

# src/planning.py
from ui_tars.planning import TaskPlanner

planner = TaskPlanner(model="ui-tars-planner")

# Decompose complex task
task = "Book a flight from New York to London for next Friday"
subtasks = planner.decompose(task)

for i, subtask in enumerate(subtasks):
    print(f"{i+1}. {subtask}")

# Output:
# 1. Open browser
# 2. Navigate to flight booking website
# 3. Enter departure city: New York
# 4. Enter destination: London
# 5. Select date: next Friday
# 6. Search for flights
# 7. Select best option
# 8. Enter passenger details
# 9. Complete booking

State Tracking

# src/state.py
from ui_tars.state import AgentState

state = AgentState()

# Update state after each action
state.update(
    current_task="Book flight",
    completed_steps=["Open browser", "Navigate to website"],
    current_step="Enter departure city",
    remaining_steps=["Enter destination", "Select date", ...],
    screenshots=[screenshot_1, screenshot_2]
)

# Get progress
progress = state.get_progress()
print(f"Progress: {progress['percentage']}%")

Step 4: Action Execution

Basic Actions

# src/actions.py
from ui_tars.actions import ActionExecutor

executor = ActionExecutor()

# Click on element
executor.click(element=browser_address_bar)

# Type text
executor.type(text="https://example.com", clear_first=True)

# Scroll
executor.scroll(direction="down", amount=500)

# Keyboard shortcuts
executor.hotkey("ctrl", "f")  # Open find dialog

Complex Interactions

# Drag and drop
executor.drag_and_drop(
    source=drag_source_element,
    target=drag_target_element
)

# Right-click context menu
executor.right_click(element=file_element)
executor.click(element=menu_delete_option)

# Hover for tooltips
executor.hover(element=help_icon)
tooltip_text = executor.capture_tooltip()

Step 5: Complete Workflow

End-to-End Example

# src/workflow.py
from ui_tars import UIAgent
from ui_tars.vision import ScreenCapture, ElementDetector
from ui_tars.planning import TaskPlanner
from ui_tars.actions import ActionExecutor

class AutomationWorkflow:
    def __init__(self):
        self.agent = UIAgent()
        self.capture = ScreenCapture()
        self.detector = ElementDetector()
        self.planner = TaskPlanner()
        self.executor = ActionExecutor()
    
    def run(self, task: str):
        """Execute complete automation workflow."""
        
        # 1. Plan the task
        subtasks = self.planner.decompose(task)
        
        # 2. Execute each subtask
        for subtask in subtasks:
            print(f"Executing: {subtask}")
            
            # Capture current state
            screenshot = self.capture.capture()
            
            # Detect relevant elements
            elements = self.detector.detect_elements(screenshot)
            
            # Plan action for this subtask
            action = self.agent.plan_action(subtask, elements, screenshot)
            
            # Execute action
            result = self.executor.execute(action)
            
            # Verify result
            if not self.verify_result(subtask, screenshot):
                print(f"Warning: {subtask} may not have completed correctly")
        
        print("Task completed!")

# Usage
workflow = AutomationWorkflow()
workflow.run("Open Chrome, navigate to google.com, search for 'AI agents'")

Advanced Features

Multi-Step Reasoning

# src/reasoning.py
from ui_tars.reasoning import ReasoningEngine

engine = ReasoningEngine()

def handle_error(error_screenshot: str, last_action: str) -> dict:
    """Reason about errors and suggest recovery."""
    
    analysis = engine.analyze(
        screenshot=error_screenshot,
        last_action=last_action,
        expected_state="login_success"
    )
    
    return {
        'error_type': analysis.error_type,
        'cause': analysis.cause,
        'recovery_action': analysis.recovery_action
    }

# Example: Login failed
result = handle_error(
    error_screenshot=login_error_screen,
    last_action="click_login_button"
)
print(f"Error: {result['error_type']}")
print(f"Recovery: {result['recovery_action']}")

Learning from Experience

# src/learning.py
from ui_tars.learning import ExperienceLearner

learner = ExperienceLearner()

# Store successful action sequences
learner.record_success(
    task="login_to_website",
    action_sequence=[
        ("click", "username_field"),
        ("type", "my_username"),
        ("click", "password_field"),
        ("type", "my_password"),
        ("click", "login_button")
    ],
    screenshot_sequence=[s1, s2, s3, s4, s5]
)

# Retrieve similar patterns
similar = learner.find_similar("sign_in_to_app")

Cross-Application Workflows

# src/cross_app.py
async def cross_application_workflow():
    """Work across multiple applications."""
    
    # Start in Chrome
    chrome_screenshot = capture.capture()
    chrome_elements = detector.detect_elements(chrome_screenshot)
    
    # Find and click link that opens another app
    link = find_element(chrome_elements, "Open in Desktop App")
    executor.click(link)
    
    # Wait for new app to open
    await asyncio.sleep(2)
    
    # Now work in the new app
    new_app_screenshot = capture.capture()
    new_app_elements = detector.detect_elements(new_app_screenshot)
    
    # Continue workflow
    ...

Best Practices

1. Error Recovery

async def robust_execute(action: dict, max_retries: int = 3):
    """Execute action with error recovery."""
    
    for attempt in range(max_retries):
        screenshot_before = capture.capture()
        result = executor.execute(action)
        
        if verify_action_success(action, screenshot_before):
            return result
        
        # Analyze failure
        error_analysis = engine.analyze_error(
            screenshot_before,
            result.error_message if result else None
        )
        
        # Adjust action
        action = error_analysis.adjusted_action
    
    raise MaxRetriesExceeded(f"Action failed after {max_retries} attempts")

2. Performance Optimization

# Cache element positions
from functools import lru_cache

@lru_cache(maxsize=100)
def get_element_position(element_id: str) -> tuple:
    """Cache element positions for faster access."""
    return detector.find_element(element_id).bbox

# Batch element detection
elements = detector.detect_elements_batch([
    screenshot1, screenshot2, screenshot3
])

3. Human-in-the-Loop

def human_confirmation_required(action: dict) -> bool:
    """Determine if human confirmation is needed."""
    
    sensitive_actions = ['delete', 'purchase', 'transfer']
    
    if any(keyword in action['type'] for keyword in sensitive_actions):
        return True
    
    return False

# Request confirmation
if human_confirmation_required(action):
    confirmation = request_human_confirmation(action)
    if not confirmation:
        skip_action(action)

Troubleshooting

Common Issues

Screen capture fails:

# Check permissions (macOS)
# System Preferences > Security & Privacy > Privacy > Screen Recording

# Check permissions (Windows)
# Ensure app has screen capture rights

Element detection inaccurate:

# Increase detection confidence threshold
elements = detector.detect_elements(
    screenshot,
    confidence_threshold=0.8  # Higher = more accurate but fewer results
)

# Use specific element types
elements = detector.detect_elements(
    screenshot,
    element_types=['button', 'input', 'link']
)

Action execution fails:

# Add delays for UI responsiveness
await asyncio.sleep(0.5)  # Wait for UI to update

# Use explicit waits
executor.wait_for_element("submit_button", timeout=10)

Resources


Last updated: May 2026