← Back to PRs

#18842: feat(telegram): add /imagequality command for uncompressed image delivery

by frankekn open 2026-02-17 04:04 View on GitHub →
channel: telegram channel: whatsapp-web size: M
## 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