Skip to main content

Overview

Every agent comes with a beautiful web UI out of the box. The interface supports both static customization (header/intro) and native UI components that stream rich content progressively to users.

Default Web UI

When you deploy your agent, it automatically gets a web interface accessible at your agent’s URL. The default UI includes:
  • Chat Interface: A modern, responsive chat interface
  • Message History: Automatic conversation history management
  • Real-time Streaming: Support for streaming responses
  • Native UI Components: Rich components like thinking bubbles, code blocks, tables, and more
  • Mobile Responsive: Works seamlessly on all devices
  • Auto RTL Support: Automatically supports right-to-left languages

Native UI Components

Cycls provides native UI components that render beautifully in the chat interface. Simply yield structured objects to display rich content that streams progressively.

Text

Plain strings are rendered as markdown text with full formatting support.
@cycls.app()
async def app(context):
    yield "Hello! Here's some **bold** and *italic* text."
    yield "\n\n## A Heading\n\nAnd a paragraph below it."

Thinking Bubbles

Show your agent’s reasoning process with collapsible thinking bubbles.
@cycls.app()
async def app(context):
    yield {"type": "thinking", "thinking": "Let me analyze this question..."}
    yield {"type": "thinking", "thinking": "Considering multiple approaches..."}
    yield "Based on my analysis, here's the answer:"

Code Blocks

Display syntax-highlighted code with language detection.
@cycls.app()
async def app(context):
    yield {
        "type": "code",
        "code": "def hello():\n    print('Hello, World!')",
        "language": "python"
    }

Tables

Stream tables row-by-row for progressive rendering.
@cycls.app()
async def app(context):
    yield {
        "type": "table",
        "headers": ["Name", "Age", "City"],
        "rows": [
            ["Alice", "30", "New York"],
            ["Bob", "25", "San Francisco"],
            ["Charlie", "35", "Chicago"]
        ]
    }

Callouts

Display styled callout boxes for important information.
@cycls.app()
async def app(context):
    yield {
        "type": "callout",
        "callout": "This operation completed successfully!",
        "style": "success",
        "title": "Success"
    }

    yield {
        "type": "callout",
        "callout": "Please review before proceeding.",
        "style": "warning",
        "title": "Warning"
    }

    yield {
        "type": "callout",
        "callout": "Here's some helpful information.",
        "style": "info",
        "title": "Info"
    }

    yield {
        "type": "callout",
        "callout": "An error occurred during processing.",
        "style": "error",
        "title": "Error"
    }
Available styles: success, warning, info, error

Images

Display images with optional captions.
@cycls.app()
async def app(context):
    yield {
        "type": "image",
        "src": "https://example.com/image.png",
        "alt": "Description of image",
        "caption": "Figure 1: An example image"
    }

Status Indicators

Show progress or status updates during long operations.
@cycls.app()
async def app(context):
    yield {"type": "status", "status": "Processing your request..."}
    # ... do work ...
    yield {"type": "status", "status": "Almost done..."}
    yield "Here are the results!"

Component Reference

TypeKey FieldsDescription
texttextMarkdown-formatted text
thinkingthinkingCollapsible reasoning bubble
codecode, languageSyntax-highlighted code block
tableheaders, rowsStreaming table
calloutcallout, style, titleStyled alert box
imagesrc, alt, captionImage with caption
statusstatusProgress indicator

Header and Intro Customization

You can also customize the header and introduction sections using HTML and TailwindCSS:
import cycls
import urllib.parse

header = """
<raw>
<div class="flex flex-col border border-gray-200 rounded-lg bg-white p-6 my-12 max-w-7xl mx-auto">
  <div class="text-3xl font-bold text-gray-900 mb-3">
    Welcome to My Agent
  </div>
  <p class="text-gray-600 text-base">
    Your AI-powered assistant for exploring new ideas.
  </p>
</div>
</raw>
"""

intro = f"""
<div class="py-3">
  <div class="flex flex-wrap gap-3 justify-center">
    <a href="https://cycls.com/send/{urllib.parse.quote('Tell me about Python')}" class="px-4 py-2 border rounded-xl hover:shadow-lg">
      Tell me about Python
    </a>
    <a href="https://cycls.com/send/{urllib.parse.quote('Write a poem')}" class="px-4 py-2 border rounded-xl hover:shadow-lg">
      Write a poem
    </a>
  </div>
</div>
"""

@cycls.app(copy_public=["logo.png"], header=header, intro=intro)
async def app(context):
    yield "Hello! How can I help you today?"

app.local()

Styling Guidelines

  • HTML Support: Full HTML5 support with inline styles
  • TailwindCSS: Complete TailwindCSS framework available
  • Raw Tags: Wrap custom HTML in <raw> tags to prevent escaping
  • Responsive Design: Use TailwindCSS responsive classes for mobile compatibility
  • Clickable Links: Use urllib.parse.quote to encode messages in links
Create clickable links that automatically send encoded text to the chat:
import urllib.parse

@cycls.app()
async def app(context):
    link = f"https://cycls.com/send/{urllib.parse.quote('Tell me more')}"
    yield f"Click here to [learn more]({link})"
[Link Text](https://cycls.com/send/Encoded%20message)

Custom Frontend Applications

You can connect any custom frontend to your agent using the OpenAI-compatible API at /chat/completions or the Cycls Protocol at /chat/cycls.

Next Steps

Agent API

Learn about the built-in REST API and streaming protocols.