QuotLy Style Sticker
How To Call (Agent)
- Build payload with required
selected_messages.
- When available, include event metadata for dedupe:
context.event.channel (example: telegram)
context.event.update_id (preferred)
- fallback keys:
event_id, delivery_id, id
- Run:
python3 scripts/openclaw_quote_autoreply.py --input <json-file-or->
- Use tool-emitted
MEDIA: for delivery.
- Final assistant text must be empty.
Input
- Required:
selected_messages (array, must not be empty)
- Optional:
context.event for dedupe accuracy
channel (string)
update_id (string or number, preferred)
event_id / delivery_id / id (fallback keys)
- Each item structure:
{
"message": {
"message_id": 2002,
"text": "Forwarded message content",
"forward_from": {
"type": "hidden_user", // optional, indicates hidden user
"id": 123456789, // optional, user id
"first_name": "张", // required, first name or nickname
"last_name": "三", // optional, last name
"avatar_url": "", // optional, avatar url or base64 data (from user profile or platform API)
"status_url": "" // optional, status url or base64 data (from user profile or platform API)
}
},
// Optional: override message fields
"overwrite_message": {
"text": "哈哈哈哈哈",
"forward_from": {
"avatar_url": "", // from user profile or platform API
"status_url": "" // from user profile or platform API
},
"entities": [ // optional, text formatting entities
{"type": "bold", "offset": 0, "length": 4},
{"type": "italic", "offset": 5, "length": 4}
]
}
}
- Optional canvas:
width, height, scale, max_width, border_radius, picture_radius, background_color
Entities (Text Formatting)
The skill supports Telegram-style message entities for text formatting:
[
{"type": "bold", "offset": 0, "length": 5},
{"type": "italic", "offset": 6, "length": 6},
{"type": "url", "offset": 13, "length": 15, "url": "https://example.com"}
]
Supported types: mention, hashtag, cashtag, bot_command, url, email, phone_number, bold, italic, underline, strikethrough, spoiler, code, pre, text_link, text_mention, custom_emoji
Entity fields:
type (required) - entity type
offset (required) - UTF-8 offset in text
length (required) - UTF-8 length
url (optional) - for text_link type
user (optional) - for text_mention type
language (optional) - for pre type
custom_emoji_id (optional) - for custom_emoji type
Field Mapping
- Quote text:
overwrite_message.text > message.text
- Name/avatar:
overwrite_message.forward_from > message.forward_from
- Text formatting (entities):
overwrite_message.entities > message.entities > message.caption_entities
Output
- stdout includes:
Quote sticker generated.
MEDIA:<absolute-path-to-webp>
- For duplicate retries detected within dedupe window, generation is skipped and no
MEDIA: line is emitted.
Environment Variables
QUOTLY_API_URL - QuotLy API endpoint (default: https://bot.lyo.su/quote/generate).
QUOTLY_API_ALLOW_HOSTS - Comma-separated list of allowed API hosts (e.g., bot.lyo.su). When set, the skill will only contact hosts in this list.
QUOTLY_AUDIT_LOG - Set to 1, true, or yes to enable audit logging to stderr.
QUOTLY_DEDUP_WINDOW_SECONDS - Suppress duplicate requests for the same event/payload within this window (default: 180). Set to 0 to disable.
Dedupe Key (How _build_dedupe_key reads input)
_build_dedupe_key(input_payload) resolves keys in this order:
context.event.update_id (or event_id / delivery_id / id)
event.update_id (or event_id / delivery_id / id) when context.event is missing
context.event.update.update_id (nested update object)
- Fallback: stable hash of
selected_messages
Recommended wrapper payload:
{
"context": {
"event": {
"channel": "telegram",
"update_id": 123456789
}
},
"selected_messages": [
{
"message": {
"message_id": 2002,
"text": "Forwarded message content"
}
}
]
}
Security Notes
- This skill sends message content to an external API to generate stickers.
- SSRF Protection: Multiple layers of protection are implemented:
- Hostname validation blocks internal/private IPs, localhost, and metadata endpoints
- DNS rebinding protection: resolves hostnames and validates resolved IPs
- Path traversal prevention: blocks
.. and suspicious path patterns
- URL credentials stripping: removes username/password from URLs
- Request Limits: Maximum payload size 1MB, maximum response size 10MB
- Audit Logging: Enable with
QUOTLY_AUDIT_LOG=1 to log API requests and responses for security monitoring
- In sensitive environments, always set
QUOTLY_API_ALLOW_HOSTS to restrict which hosts the skill can contact.
- Avatar and status URLs from user input are passed to the rendering service; ensure input comes from trusted sources.
Reply Rule
- Do not output any final text.
1---2name: quotly-style-sticker3description: Generate QuotLy-style stickers from forwarded messages and return one MEDIA path for auto-send. Use when users ask to create quote stickers from selected forwarded messages or quoted messages in groups.4---5
6# QuotLy Style Sticker
7
8## How To Call (Agent)
9
101. Build payload with required `selected_messages`.
112. When available, include event metadata for dedupe:
12 - `context.event.channel` (example: `telegram`)
13 - `context.event.update_id` (preferred)
14 - fallback keys: `event_id`, `delivery_id`, `id`
153. Run:
16 - `python3 scripts/openclaw_quote_autoreply.py --input <json-file-or->`
174. Use tool-emitted `MEDIA:` for delivery.
185. Final assistant text must be empty.
19
20## Input
21
22- Required: `selected_messages` (array, must not be empty)
23- Optional: `context.event` for dedupe accuracy
24 - `channel` (string)
25 - `update_id` (string or number, preferred)
26 - `event_id` / `delivery_id` / `id` (fallback keys)
27- Each item structure:
28 ```json5
29 {
30 "message": {
31 "message_id": 2002,
32 "text": "Forwarded message content",
33 "forward_from": {
34 "type": "hidden_user", // optional, indicates hidden user
35 "id": 123456789, // optional, user id
36 "first_name": "张", // required, first name or nickname
37 "last_name": "三", // optional, last name
38 "avatar_url": "", // optional, avatar url or base64 data (from user profile or platform API)
39 "status_url": "" // optional, status url or base64 data (from user profile or platform API)
40 }
41 },
42 // Optional: override message fields
43 "overwrite_message": {
44 "text": "哈哈哈哈哈",
45 "forward_from": {
46 "avatar_url": "", // from user profile or platform API
47 "status_url": "" // from user profile or platform API
48 },
49 "entities": [ // optional, text formatting entities
50 {"type": "bold", "offset": 0, "length": 4},
51 {"type": "italic", "offset": 5, "length": 4}
52 ]
53 }
54 }
55 ```
56- Optional canvas: `width`, `height`, `scale`, `max_width`, `border_radius`, `picture_radius`, `background_color`
57
58## Entities (Text Formatting)
59
60The skill supports Telegram-style message entities for text formatting:
61
62```json5
63[
64 {"type": "bold", "offset": 0, "length": 5},
65 {"type": "italic", "offset": 6, "length": 6},
66 {"type": "url", "offset": 13, "length": 15, "url": "https://example.com"}
67]
68```
69
70**Supported types:** `mention`, `hashtag`, `cashtag`, `bot_command`, `url`, `email`, `phone_number`, `bold`, `italic`, `underline`, `strikethrough`, `spoiler`, `code`, `pre`, `text_link`, `text_mention`, `custom_emoji`
71
72**Entity fields:**
73- `type` (required) - entity type
74- `offset` (required) - UTF-8 offset in text
75- `length` (required) - UTF-8 length
76- `url` (optional) - for `text_link` type
77- `user` (optional) - for `text_mention` type
78- `language` (optional) - for `pre` type
79- `custom_emoji_id` (optional) - for `custom_emoji` type
80
81## Field Mapping
82
83- Quote text:
84 - `overwrite_message.text` > `message.text`
85- Name/avatar:
86 - `overwrite_message.forward_from` > `message.forward_from`
87- Text formatting (entities):
88 - `overwrite_message.entities` > `message.entities` > `message.caption_entities`
89
90## Output
91
92- stdout includes:
93 - `Quote sticker generated.`
94 - `MEDIA:<absolute-path-to-webp>`
95- For duplicate retries detected within dedupe window, generation is skipped and no `MEDIA:` line is emitted.
96
97## Environment Variables
98
99- `QUOTLY_API_URL` - QuotLy API endpoint (default: `https://bot.lyo.su/quote/generate`).
100- `QUOTLY_API_ALLOW_HOSTS` - Comma-separated list of allowed API hosts (e.g., `bot.lyo.su`). When set, the skill will only contact hosts in this list.
101- `QUOTLY_AUDIT_LOG` - Set to `1`, `true`, or `yes` to enable audit logging to stderr.
102- `QUOTLY_DEDUP_WINDOW_SECONDS` - Suppress duplicate requests for the same event/payload within this window (default: `180`). Set to `0` to disable.
103
104## Dedupe Key (How `_build_dedupe_key` reads input)
105
106`_build_dedupe_key(input_payload)` resolves keys in this order:
107
1081. `context.event.update_id` (or `event_id` / `delivery_id` / `id`)
1092. `event.update_id` (or `event_id` / `delivery_id` / `id`) when `context.event` is missing
1103. `context.event.update.update_id` (nested update object)
1114. Fallback: stable hash of `selected_messages`
112
113Recommended wrapper payload:
114
115```json
116{
117 "context": {
118 "event": {
119 "channel": "telegram",
120 "update_id": 123456789
121 }
122 },
123 "selected_messages": [
124 {
125 "message": {
126 "message_id": 2002,
127 "text": "Forwarded message content"
128 }
129 }
130 ]
131}
132```
133
134## Security Notes
135
136- This skill sends message content to an external API to generate stickers.
137- **SSRF Protection**: Multiple layers of protection are implemented:
138 - Hostname validation blocks internal/private IPs, localhost, and metadata endpoints
139 - DNS rebinding protection: resolves hostnames and validates resolved IPs
140 - Path traversal prevention: blocks `..` and suspicious path patterns
141 - URL credentials stripping: removes username/password from URLs
142- **Request Limits**: Maximum payload size 1MB, maximum response size 10MB
143- **Audit Logging**: Enable with `QUOTLY_AUDIT_LOG=1` to log API requests and responses for security monitoring
144- In sensitive environments, always set `QUOTLY_API_ALLOW_HOSTS` to restrict which hosts the skill can contact.
145- Avatar and status URLs from user input are passed to the rendering service; ensure input comes from trusted sources.
146
147## Reply Rule
148
149- Do not output any final text.