#18842: feat(telegram): add /imagequality command for uncompressed image delivery
channel: telegram
channel: whatsapp-web
size: M
Cluster:
Messaging Platform Improvements
## Summary
Add a `/imagequality` slash command for Telegram that lets users control whether images are sent as compressed photos (`sendPhoto`) or uncompressed documents (`sendDocument`).
### Problem
Telegram applies lossy compression to images sent via `sendPhoto`. For users sharing high-resolution screenshots, architecture diagrams, or detailed graphics, this double-compression pipeline (OpenClaw optimization + Telegram re-compression) significantly degrades image quality.
There is currently no way for users to opt out of this compression.
### Solution
**New `/imagequality` slash command** with two modes:
| Mode | Behavior |
|------|----------|
| `normal` (default) | Images optimized by OpenClaw and sent via `sendPhoto` — existing behavior, unchanged |
| `high` | Optimization skipped, images sent via `sendDocument` with 50MB cap (Telegram upload limit) — lossless delivery |
**Usage:**
- `/imagequality` — show current setting
- `/imagequality normal` — compressed photos (default)
- `/imagequality high` — uncompressed documents
### Design Decisions
- **Per-chat preference** stored as a JSON file under `<stateDir>/telegram/image-quality/<account>/<chatId>.json`, following the existing file-based state pattern (similar to `update-offset-store`, `pairing-store`).
- **Both send paths patched**: `send.ts` (proactive tool calls) and `bot/delivery.ts` (agent reply media).
- **GIFs unaffected** — always sent via `sendAnimation` regardless of quality setting, preserving auto-play behavior.
- **50MB maxBytes for high mode** — bypasses the default 6MB image cap in `loadWebMedia`, matching Telegram `sendDocument` upload limit.
- **Provider-scoped command** — only registered on Telegram via new `providers` field on `ChatCommandDefinition`, which is a generic mechanism other commands can use in the future.
- **Backward compatible** — default is `normal`, file absence = normal. Zero behavior change for existing users.
### Files Changed (9)
| File | Change |
|------|--------|
| `src/telegram/image-quality-store.ts` | **New** — per-chat quality preference store (read/write/normalize) |
| `src/telegram/send.ts` | Read quality preference; skip optimization + force `sendDocument` when `high`; 50MB cap |
| `src/telegram/bot/delivery.ts` | Same as above for reply delivery path; added `accountId` param; quality read hoisted above media loop |
| `src/telegram/bot-native-commands.ts` | `/imagequality` command handler |
| `src/telegram/bot-message-dispatch.ts` | Pass `accountId` to `deliverReplies` |
| `src/auto-reply/commands-registry.data.ts` | Register `imagequality` command |
| `src/auto-reply/commands-registry.ts` | Filter commands by `providers` field |
| `src/auto-reply/commands-registry.types.ts` | Add `providers?: string[]` to `ChatCommandDefinition` |
| `src/web/media.ts` | Add optional `optimizeImages` param to `loadWebMedia` public API |
### Testing
- `tsc --noEmit` ✅
- `pnpm lint` ✅ (0 errors)
- `pnpm format` ✅
- 57 related tests passing (commands-registry, send, delivery)
- Manual testing: confirmed `sendDocument` delivers uncompressed 4800×13280 PNG via Telegram
### Future Enhancements
This PR establishes the foundation for more granular image quality control. Potential follow-ups:
- **Resolution presets** (`/imagequality 1080p`, `/imagequality 4k`, `/imagequality original`) — resize to specific max dimensions instead of binary compress/raw
- **Per-message override** — `asDocument` parameter on the `message` tool for one-off high-quality sends without changing the default
- **Cross-platform** — extend to WhatsApp (which has similar compression issues) and other channels
- **Config-level default** — `channels.telegram.imageQuality: "high"` for gateway-wide setting
### Related
Closes the image compression quality gap discussed in the community. Telegram's `sendPhoto` compression is a known pain point for users sharing technical diagrams and high-res screenshots.
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
Adds a `/imagequality` Telegram slash command that lets users toggle between compressed photo delivery (`sendPhoto`, default) and uncompressed document delivery (`sendDocument`) for images. The implementation introduces a generic `providers` field on `ChatCommandDefinition` to scope commands to specific channels.
- New `image-quality-store.ts` provides per-chat quality preferences via file-based JSON state (atomic writes, version-checked reads, path-sanitized IDs), following existing patterns like `pairing-store` and `update-offset-store`
- Both send paths patched: `send.ts` (proactive tool calls) and `bot/delivery.ts` (agent reply media) — each reads the quality preference, disables image optimization when `high`, passes 50MB `maxBytes` for Telegram's `sendDocument` limit, and overrides media kind from `"image"` to `"document"`
- GIFs remain unaffected — `isGif` check takes priority before `kind` routing
- Provider-scoped command filtering added to `listNativeCommandSpecs`, `listNativeCommandSpecsForConfig`, and `findCommandByNativeName` with correct short-circuit logic (no provider = show all, specific provider = filter)
- Backward compatible: default is `normal`, file absence = `normal`, no behavior change for existing users
<h3>Confidence Score: 5/5</h3>
- This PR is safe to merge — clean implementation following established patterns with no logic errors or regressions.
- All 9 changed files were reviewed thoroughly. The implementation follows existing file-based state patterns, both send paths are correctly patched with proper maxBytes handling (50MB for high-quality mode), the provider-scoping mechanism is correctly implemented with proper filter logic, and the feature is fully backward compatible (default behavior unchanged). The previously flagged 6MB cap issue has been addressed in follow-up commit e4ddffe. No new issues found.
- No files require special attention.
<sub>Last reviewed commit: 9445c77</sub>
<!-- greptile_other_comments_section -->
<!-- /greptile_comment -->
Most Similar PRs
#22434: feat(telegram): support sending original quality images
by godenjan · 2026-02-21
81.7%
#21898: fix(telegram): auto-detect captionable messages for editMessageCaption
by ptrkstr · 2026-02-20
75.9%
#18915: fix(telegram): pass video width/height to sendVideo to prevent portra…
by storyarcade · 2026-02-17
74.9%
#21029: Feature/telegram bot avatar clean
by aleonnet · 2026-02-19
73.9%
#21309: feat(telegram): support outbound media groups (albums) via sendMedi...
by smysle · 2026-02-19
73.4%
#21276: fix(telegram): stabilize partial finalization and MEDIA dedupe (AI-...
by HOYALIM · 2026-02-19
72.6%
#17953: fix(telegram): prevent silent message loss and duplicate messages i...
by zuyan9 · 2026-02-16
71.6%
#19673: fix(telegram): avoid starting streaming replies with only 1-2 words
by emanuelst · 2026-02-18
71.5%
#16018: feat: add image support to /v1/chat/completions endpoint
by sebastienb · 2026-02-14
71.5%
#14057: feat(telegram): add ignoreMediaTypes config to skip specific inboun...
by pavelsamoylenko · 2026-02-11
71.3%