#22290: Fix WhatsApp reply quoted-media audio transcription resolution
channel: whatsapp-web
size: M
Cluster:
Media Handling Improvements
## Summary
- resolve quoted media for reply messages when current inbound message has no media
- add deterministic fallback by quoted reply message id using a short-lived in-memory media map
- preserve the existing transcription path by attaching resolved mediaPath/mediaType as normal inbound media
## Scope
- no logging/metrics additions
- no broad refactor
- only WhatsApp web inbound media resolution + minimal tests
## Tests
- `pnpm exec vitest run src/web/monitor-inbox.streams-inbound-messages.test.ts src/web/inbound.test.ts src/web/inbound/media.node.test.ts`
- `pnpm exec oxlint --type-aware src/web/inbound/monitor.ts src/web/inbound/extract.ts src/web/monitor-inbox.streams-inbound-messages.test.ts`
- `pnpm exec oxfmt --check src/web/inbound/extract.ts src/web/inbound/monitor.ts src/web/monitor-inbox.streams-inbound-messages.test.ts`
## Note
- repository-wide `pnpm exec tsc --noEmit -p tsconfig.json --pretty false` currently fails due unrelated pre-existing test typing errors in:
- `src/discord/send.components.test.ts`
- `src/gateway/server.chat.gateway-server-chat-b.e2e.test.ts`
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
This PR resolves WhatsApp audio transcription for reply messages by implementing a three-tier media resolution strategy:
1. **Direct resolution**: Extract quoted message inline and attempt to download its media
2. **Fallback cache**: Store recently processed media in a short-lived in-memory map (10min TTL, max 128 entries) indexed by message ID
3. **Deterministic lookup**: When inline media unavailable, fall back to cached media using the quoted message's ID
The implementation refactors `describeReplyContext` by extracting a new `extractQuotedMessage` helper that returns the structured quoted context (id, participantJid, message), enabling media resolution without duplicating extraction logic. The cache uses a simple LRU-like eviction (deletes oldest when exceeding 128 entries) and expires entries after 10 minutes to prevent unbounded memory growth.
<h3>Confidence Score: 4/5</h3>
- This PR is safe to merge with minimal risk
- The implementation is clean and well-tested with focused changes to media resolution logic. Tests cover both the inline quoted media resolution and fallback cache scenarios. The in-memory cache has appropriate bounds (TTL + max entries) to prevent memory leaks. The refactoring to extract `extractQuotedMessage` improves code reuse without changing existing behavior.
- No files require special attention
<sub>Last reviewed commit: 4545ea7</sub>
<!-- greptile_other_comments_section -->
<sub>(2/5) Greptile learns from your feedback when you react with thumbs up/down!</sub>
<!-- /greptile_comment -->
Most Similar PRs
#19303: Fix WhatsApp internal error leakage + cron.run timeout defaults
by koala73 · 2026-02-17
78.8%
#23148: fix: forward mediaLocalRoots in whatsapp plugin sendMedia
by MunemHashmi · 2026-02-22
77.3%
#9606: fix: pass fileName to WhatsApp document messages
by AytuncYildizli · 2026-02-05
76.1%
#20594: feat(whatsapp): batch multi-image messages via debouncer
by arniesaha · 2026-02-19
75.0%
#4390: fix(whatsapp): allow media from allowlisted groups without groupAllow…
by Sarang19114 · 2026-01-30
74.3%
#12700: fix(tts): deliver WhatsApp voice as opus bubble instead of MP3 (#12...
by lailoo · 2026-02-09
74.2%
#8052: fix(whatsapp): strip leading whitespace from outbound messages
by FelixFoster · 2026-02-03
74.0%
#16655: fix(whatsapp): resolve reply-to sender E.164 for LID JIDs (have bot...
by mascarenhas · 2026-02-15
74.0%
#8042: feat(telegram): add media index for reply-to media lookup
by batumilove · 2026-02-03
73.9%
#9727: fix(whatsapp): retry reconnect loop on initial connection failure
by luizlf · 2026-02-05
73.7%