Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.heylua.ai/llms.txt

Use this file to discover all available pages before exploring further.

What Are Channel-aware Prompts?

Channel-aware prompts let you customize your agent’s persona and skill context based on whether the user is interacting via voice or text. This is rarely needed — the platform handles most channel-specific behavior automatically. But when you have genuinely different communication needs (e.g., conversational tone on voice, structured lists on text), this feature lets you optimize for each channel.

Rule of thumb:

If you need to ask “should I say this differently on voice vs text?”, you probably don’t need channel-aware prompts. Most agents should keep a simple string persona and context.

When to Use Channel-aware Prompts

Use the polymorphic form only if you have a measurably different need:

✅ Use it for:

  • Conversational tone on voice, structured formatting on text
  • Voice-specific instructions (e.g., “avoid markdown”)
  • Text-specific instructions (e.g., “use ::: list-item blocks”)

❌ Don't use it for:

  • Minor tweaks or polish
  • The same concept explained differently
  • Most agents (keep it simple)

Syntax

Both persona and skill context accept the polymorphic form:
// String form (recommended)
persona: "You are Alex, a friendly customer support agent"

// Object form (channel-aware)
persona: {
  base: "You are Alex, a customer support agent.",
  voice: "Speak naturally and conversationally.",
  text: "Use ::: list-item blocks when showing options."
}

Fields

  • base — Shared across all channels (optional)
  • voice — Voice-specific additions (optional, ignored on text)
  • text — Text-specific additions (optional, ignored on voice)
Strict semantics: If a channel-specific key isn’t set, it is not rendered. There is no fallback across channels.
Validation: The object must have at least one non-empty field. Empty objects ({}), empty strings (""), and objects whose only present fields are empty ({ base: "" }) are rejected at push time — pass undefined or omit the field entirely if you want no persona / context.

Examples

Example 1: Customer Support Agent

import { LuaAgent, LuaSkill } from 'lua-cli';

const agent = new LuaAgent({
  name: 'support-agent',
  
  // Base persona shared across channels
  persona: {
    base: `You are Alex, customer support specialist for TechCorp.
You help users resolve issues and find solutions.

Core responsibilities:
- Answer product questions
- Troubleshoot issues
- Process refunds and returns
- Escalate complex issues`,
    
    voice: `Speak naturally and conversationally.
Use short, clear sentences.
Ask one question at a time.`,
    
    text: `For longer explanations, break them into ::: list-item blocks.
Use the ::: actions component to show next steps.
Be concise but thorough in writing.`
  },
  
  skills: [supportSkill]
});
On voice, the agent hears:
“You are Alex… Speak naturally and conversationally. Use short, clear sentences…”
On text, the agent sees:
“You are Alex… For longer explanations, break them into ::: list-item blocks…”

Example 2: Hotel Booking Agent

const bookingSkill = new LuaSkill({
  name: 'hotel-booking',
  description: 'Book hotel rooms',
  
  context: {
    base: `Help guests find and book hotel rooms.

Key tools:
- check_availability: Find rooms by date and guest count
- create_reservation: Book a confirmed room
- cancel_reservation: Cancel existing booking`,
    
    voice: `When confirming details on a call, read them back naturally:
"So that's checking in on March 15, checking out on March 18, for 2 guests?"
Ask about special requests naturally (early check-in, late checkout, etc.)`,
    
    text: `After searching for availability, show results using ::: horizontal-list-item
blocks with images for each room. Include price, room type, and amenities.
Confirmation steps should use ::: actions component.`
  },
  
  tools: [checkAvailabilityTool, createReservationTool, cancelReservationTool]
});

Example 3: Analytics Report Skill

const reportSkill = new LuaSkill({
  name: 'analytics-reports',
  description: 'Generate and share analytics reports',
  
  context: {
    base: `Provide analytics insights using generate_report and share_report tools.
Always ask for date range and metrics before generating.`,
    
    voice: `Speak results conversationally:
"Your revenue this month is $42,000, which is up 15% from last month.
The top product is Widget X with 2,500 units sold."`,
    
    text: `Display reports using ::: list-item components for each metric.
Show charts using ::: images component.
Use ::: links to export or share the report.`
  },
  
  tools: [generateReportTool, shareReportTool]
});

Migration: From String to Object

If you start with a simple string and later realize you need channel-specific behavior, the migration is straightforward: Before:
const agent = new LuaAgent({
  name: 'my-agent',
  persona: 'You are a helpful assistant.'
});
After:
const agent = new LuaAgent({
  name: 'my-agent',
  persona: {
    base: 'You are a helpful assistant.',
    voice: 'Speak conversationally.',
    text: 'Use structured formatting.'
  }
});
All existing string personas continue to work unchanged.

Common Patterns

Pattern 1: Base + Voice Only

When you only need voice customization (text uses the base):
persona: {
  base: "Core persona description",
  voice: "Additional voice-specific instructions"
  // text is omitted — uses base on text channels
}
On voice: base + voice
On text: base (text field is not rendered)

Pattern 2: Base + Text Only

When you only need text customization (voice uses the base):
context: {
  base: "General skill context",
  text: "Formatting instructions for text channels"
  // voice is omitted — uses base on voice channels
}
On voice: base (voice field is not rendered)
On text: base + text

Pattern 3: Base + Both Channels

Full customization for both channels:
persona: {
  base: "Shared core personality",
  voice: "Voice-specific tone",
  text: "Text-specific formatting"
}
On voice: base + voice
On text: base + text

Best Practices

1

Start simple

Write a single string persona first. Add channel-aware behavior only when you discover a real need.
2

Use base for shared content

Put the core agent personality and responsibilities in base. Use voice and text only for channel-specific nuances.
3

Voice: conversational

On voice, focus on natural language flow, short sentences, and oral clarity.
4

Text: structured

On text, leverage the ::: components (list-item, actions, links, etc.) for visual clarity.
5

Don't over-optimize

Remember: the platform handles 95% of channel-specific behavior for you (voice tone, text formatting rules, etc.). Only use this feature for cases where you genuinely need different core instructions.
6

Test both channels

When using channel-aware prompts, always test in both voice and text to ensure they work as intended.

API Reference

See the persona field in LuaAgent and context field in LuaSkill for complete type signatures and examples.

Next Steps

Persona Guide

Deep dive into creating effective personas

Skill Guide

Learn about skill design and context

Text Formatting

::: component syntax for text channels

Voice Channels

How voice calls work in Lua