fix: cross-session message routing — stale closure + autoplay bugs
Root cause: switchSession and syncActiveFromSessions captured stale
`messages` from React closure, then overwrote messagesMapRef (which
was already correct) with stale data on session switch. This caused
messages to appear in wrong sessions or disappear entirely.
Fix: replace all nested setActiveSessionId-as-getter patterns with
an activeSessionIdRef that's always current. All message mutators
now read the ref directly instead of relying on closure captures.
Also fixes:
- Voice autoplay now checks if message is for active session
- Eliminates 6 nested setActiveSessionId callbacks (cleaner code)