feat: add useMessageGroups hook for unified message display (Phase 1)
Implemented data transformation layer to group raw Letta messages by ID into
unified MessageGroup objects for rendering.
Grouping Logic:
- Groups messages with same ID (e.g., reasoning + assistant share ID)
- Pairs tool_call_message with tool_return_message
- Extracts compaction alerts from user messages
- Parses multipart user messages (text + images)
- Handles orphaned tool returns defensively
- Appends streaming group as temporary FlatList item
Message Types:
- user: Regular user messages with optional images
- assistant: Assistant messages with optional reasoning
- tool_call: Tool call + return pair with optional reasoning
- tool_return_orphaned: Tool return without matching call (defensive)
- compaction: Memory compaction alerts
Streaming Integration:
- Accepts isStreaming flag and streamingState
- Appends temporary group with id='streaming' and groupKey='streaming-*'
- Server refresh replaces streaming item with real messages
Architecture:
- Pure transformation hook (no side effects)
- Type-safe with comprehensive interfaces
- ES5-compatible (no downlevelIteration or s regex flag)
- Defensive parsing throughout
This is Phase 1 of message display unification. Next phases:
- Phase 2: Create MessageGroupBubble component
- Phase 3: Integrate into ChatScreen (non-breaking)
- Phase 4: Update streaming to use groups
- Phase 5: Remove old MessageBubbleEnhanced