Load messages
RG client
→ TCP: {"action":"get_messages","chat_guid":"...","limit":50,"describe_images":true}
→ Pi4 front-door relay, then Mac fallback relay if needed
→ GET /api/v1/chat/{guid}/message (BlueBubbles)
→ Returns text messages plus attachment pseudo-messages
→ Client renders text, generic attachment, and image-description bubbles
Image description flow
BlueBubbles message attachments
→ relay detects image/* attachments
→ relay returns "[Describing image...]" pseudo-message immediately
→ relay background worker retrieves and normalizes image bytes
→ mmx vision describe runs on the Mac relay host
→ description is cached at ~/.cache/aquaping/image_descriptions.json
→ next client poll receives same pseudo-message GUID with updated text
Send message
RG client
→ TCP: {"action":"send","chat_guid":"...","text":"hello"}
→ Pi4 front-door relay, then Mac fallback relay if needed
→ POST /api/v1/message/text (BlueBubbles)
→ Client waits for response, then re-fetches messages