Overview
Industry: Retail A customer-facing kiosk that prints receipts, reads NFC loyalty cards, displays messages on screen, and lets customers request help from the AI agent. Commands:print_receipt— Print a formatted receiptread_nfc_card— Read an NFC loyalty carddisplay_message— Show a message on the kiosk screen
customer_help_requested— Fires when a customer presses the help button
Device Client
import { DeviceClient } from '@lua-ai-global/device-client';
// Simulated hardware interfaces
const printer = {
print: async (lines: string[]) => {
console.log('--- RECEIPT ---');
lines.forEach(l => console.log(l));
console.log('--- END ---');
return { printed: true, lineCount: lines.length };
},
};
const nfc = {
read: async () => ({
cardId: 'NFC-8847-2024',
memberName: 'Jane Smith',
tier: 'Gold',
points: 2450,
}),
};
const display = {
show: async (message: string, style: string) => {
console.log(`[DISPLAY ${style}] ${message}`);
return { displayed: true };
},
};
const device = new DeviceClient({
agentId: process.env.LUA_AGENT_ID!,
apiKey: process.env.LUA_API_KEY!,
deviceName: 'store-kiosk-01',
group: 'retail-kiosks',
commands: [
{
name: 'print_receipt',
description: 'Print a receipt on the kiosk thermal printer. Provide an array of text lines to print.',
inputSchema: {
type: 'object',
properties: {
lines: {
type: 'array',
items: { type: 'string' },
description: 'Array of text lines to print on the receipt',
},
header: { type: 'string', description: 'Store name or header text' },
footer: { type: 'string', description: 'Footer text (e.g., return policy)' },
},
required: ['lines'],
},
timeoutMs: 15000,
},
{
name: 'read_nfc_card',
description: 'Activate the NFC reader and scan a loyalty card. Returns member name, tier, and points balance. Prompts the customer to tap their card.',
timeoutMs: 30000,
},
{
name: 'display_message',
description: 'Show a message on the kiosk display screen',
inputSchema: {
type: 'object',
properties: {
message: { type: 'string', description: 'Message text to display' },
style: { type: 'string', enum: ['welcome', 'info', 'success', 'error'], default: 'info' },
},
required: ['message'],
},
},
],
});
device.onCommand('print_receipt', async (payload) => {
const lines: string[] = [];
if (payload.header) {
lines.push('================================');
lines.push(` ${payload.header}`);
lines.push('================================');
}
lines.push('');
lines.push(...(payload.lines || []));
lines.push('');
if (payload.footer) {
lines.push('--------------------------------');
lines.push(payload.footer);
}
lines.push(` ${new Date().toLocaleString()}`);
const result = await printer.print(lines);
return { ...result, totalLines: lines.length };
});
device.onCommand('read_nfc_card', async () => {
await display.show('Please tap your loyalty card...', 'info');
const card = await nfc.read();
await display.show(`Welcome back, ${card.memberName}!`, 'success');
return card;
});
device.onCommand('display_message', async (payload) => {
const result = await display.show(payload.message, payload.style || 'info');
return { ...result, message: payload.message };
});
async function main() {
await device.connect();
console.log('Retail kiosk online');
await display.show('Welcome! How can I help you today?', 'welcome');
// Simulate a customer pressing the help button every few minutes
setInterval(async () => {
if (Math.random() < 0.1) {
await device.trigger('customer_help_requested', {
kiosk: 'store-kiosk-01',
location: 'entrance',
timestamp: new Date().toISOString(),
});
}
}, 30000);
}
main().catch(console.error);
import asyncio
import os
import random
from datetime import datetime, timezone
from lua_device import DeviceClient, DeviceCommandDefinition
# Simulated hardware interfaces
async def printer_print(lines):
print("--- RECEIPT ---")
for line in lines:
print(line)
print("--- END ---")
return {"printed": True, "lineCount": len(lines)}
async def nfc_read():
return {
"cardId": "NFC-8847-2024",
"memberName": "Jane Smith",
"tier": "Gold",
"points": 2450,
}
async def display_show(message, style):
print(f"[DISPLAY {style}] {message}")
return {"displayed": True}
client = DeviceClient(
agent_id=os.environ["LUA_AGENT_ID"],
api_key=os.environ["LUA_API_KEY"],
device_name="store-kiosk-01",
group="retail-kiosks",
commands=[
DeviceCommandDefinition(
name="print_receipt",
description="Print a receipt on the kiosk thermal printer. Provide an array of text lines to print.",
input_schema={
"type": "object",
"properties": {
"lines": {
"type": "array",
"items": {"type": "string"},
"description": "Array of text lines to print on the receipt",
},
"header": {"type": "string", "description": "Store name or header text"},
"footer": {"type": "string", "description": "Footer text (e.g., return policy)"},
},
"required": ["lines"],
},
timeout_ms=15000,
),
DeviceCommandDefinition(
name="read_nfc_card",
description="Activate the NFC reader and scan a loyalty card. Returns member name, tier, and points balance. Prompts the customer to tap their card.",
timeout_ms=30000,
),
DeviceCommandDefinition(
name="display_message",
description="Show a message on the kiosk display screen",
input_schema={
"type": "object",
"properties": {
"message": {"type": "string", "description": "Message text to display"},
"style": {"type": "string", "enum": ["welcome", "info", "success", "error"], "default": "info"},
},
"required": ["message"],
},
),
],
)
@client.on_command("print_receipt")
async def handle_print_receipt(payload):
lines = []
if payload.get("header"):
lines.append("================================")
lines.append(f" {payload['header']}")
lines.append("================================")
lines.append("")
lines.extend(payload.get("lines", []))
lines.append("")
if payload.get("footer"):
lines.append("--------------------------------")
lines.append(payload["footer"])
lines.append(f" {datetime.now().strftime('%c')}")
result = await printer_print(lines)
return {**result, "totalLines": len(lines)}
@client.on_command("read_nfc_card")
async def handle_read_nfc_card(payload):
await display_show("Please tap your loyalty card...", "info")
card = await nfc_read()
await display_show(f"Welcome back, {card['memberName']}!", "success")
return card
@client.on_command("display_message")
async def handle_display_message(payload):
result = await display_show(payload["message"], payload.get("style", "info"))
return {**result, "message": payload["message"]}
async def main():
await client.connect()
print("Retail kiosk online")
await display_show("Welcome! How can I help you today?", "welcome")
# Simulate a customer pressing the help button every few minutes
while True:
if random.random() < 0.1:
await client.trigger("customer_help_requested", {
"kiosk": "store-kiosk-01",
"location": "entrance",
"timestamp": datetime.now(timezone.utc).isoformat(),
})
await asyncio.sleep(30)
asyncio.run(main())
Agent-Side Trigger Handler
// src/triggers/customer-help.ts
import { defineDeviceTrigger } from 'lua-cli';
import { z } from 'zod';
export const customerHelp = defineDeviceTrigger({
name: 'customer-help-requested',
description: 'Fired when a customer presses the help button on a retail kiosk',
payloadSchema: z.object({
kiosk: z.string(),
location: z.string(),
timestamp: z.string(),
}),
execute: async (payload, { agent, device }) => {
await agent.chat(
`A customer at kiosk "${payload.kiosk}" (${payload.location}) ` +
`is requesting help. Please display a helpful greeting and ` +
`ask what they need assistance with.`
);
},
});
Agent Configuration
// src/index.ts
import { LuaAgent, LuaSkill } from 'lua-cli';
import { customerHelp } from './triggers/customer-help';
const retailSkill = new LuaSkill({
name: 'retail-kiosk',
description: 'Retail kiosk customer service',
context: `
You operate customer-facing retail kiosks.
Device tools:
- print_receipt: Print receipts. Format nicely with header, items, and footer.
- read_nfc_card: Scan loyalty cards. Use when customer wants to check points or redeem rewards.
- display_message: Show messages on screen. Use 'welcome' for greetings, 'success' for confirmations.
Guidelines:
- Always greet customers warmly
- After reading a loyalty card, mention their tier and points
- Include store name in receipt headers
- Add return policy in receipt footers
`,
tools: [],
});
export const agent = new LuaAgent({
name: 'retail-assistant',
persona: `You are a friendly retail assistant at a kiosk. Help customers check loyalty points,
print receipts, and find information. Be warm, concise, and helpful.`,
skills: [retailSkill],
deviceTriggers: [customerHelp],
});
Next Steps
CDN Uploads
Upload screenshots and logs from kiosk devices
Smart Office
Facilities management example
Warehouse Scanner
Logistics and inventory management
Agent Tools
How device commands become agent tools

